summaryrefslogtreecommitdiff
path: root/demux.go
blob: 632630d120a64f359e717dab890a83fb432267bd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
package binproto

type urReturn struct {
	ut   UnitType
	data interface{}
}

type Demux struct {
	ur            UnitReader
	events, other chan urReturn
	err           error
}

func NewDemux(ur UnitReader) (d *Demux) {
	d = &Demux{
		ur:     ur,
		events: make(chan urReturn),
		other:  make(chan urReturn),
		err:    nil}
	go d.demux()
	return
}

func (d *Demux) demux() {
	inEvent := false
	nesting := 0

	for {
		ut, data, err := d.ur.ReadUnit()
		if err != nil {
			d.err = err
			close(d.events)
			close(d.other)
			return
		}

		if inEvent {
			switch ut {
			case UTList, UTIdKVMap, UTTextKVMap:
				nesting++
			case UTTerm:
				nesting--
			}

			d.events <- urReturn{ut, data}

			if nesting <= 0 {
				inEvent = false
			}
		} else if ut == UTEvent {
			d.events <- urReturn{ut, data}
			inEvent = true
			nesting = 0
		} else {
			d.other <- urReturn{ut, data}
		}
	}
}

type PartUnitReader struct {
	ch chan urReturn
	d  *Demux
}

func (d *Demux) Events() *PartUnitReader { return &PartUnitReader{d.events, d} }
func (d *Demux) Other() *PartUnitReader  { return &PartUnitReader{d.other, d} }

func (pur *PartUnitReader) ReadUnit() (UnitType, interface{}, error) {
	urr, ok := <-pur.ch
	if !ok {
		return 0, nil, pur.d.err
	}

	return urr.ut, urr.data, nil
}