package models import ( "bufio" "bytes" "regexp" "sync" ) var reg = regexp.MustCompile("(?sm)^@begin .+?(^| )@end") type Log struct { Name string Entries []Entry } func (l *Log) UnmarshalText(in []byte) error { ch := l.getLogUnarshalChan(in) for entry := range ch { l.Entries = append(l.Entries, entry) } return nil } func scanLog(data []byte, atEOF bool) (advance int, token []byte, err error) { if atEOF && len(data) == 0 { // done return 0, nil, nil } m := reg.FindIndex(data) if len(m) == 0 && atEOF { // all trash return len(data), nil, nil } else if len(m) == 0 && !atEOF { // get more return 0, nil, nil } return m[1], data[m[0]:m[1]], nil } func (l *Log) getLogUnarshalChan(in []byte) chan Entry { size := len(in) / 10 // rough estimation ch := make(chan Entry, size) var wg sync.WaitGroup read := bytes.NewReader(in) scan := bufio.NewScanner(read) scan.Split(scanLog) for scan.Scan() { wg.Add(1) go func(field []byte) { defer wg.Done() f := new(Entry) err := f.UnmarshalText(field) if err != nil { return } ch <- *f }(scan.Bytes()) } go func() { wg.Wait() close(ch) }() return ch }