✨ Entry implements TextUnmarshaler
This commit is contained in:
		
					parent
					
						
							
								2d68691408
							
						
					
				
			
			
				commit
				
					
						c45acd57c4
					
				
			
		
					 2 changed files with 112 additions and 5 deletions
				
			
		|  | @ -1,8 +1,10 @@ | |||
| package models | ||||
| 
 | ||||
| import ( | ||||
| 	"bufio" | ||||
| 	"bytes" | ||||
| 	"errors" | ||||
| 	"regexp" | ||||
| 	"strings" | ||||
| 	"sync" | ||||
| 	"time" | ||||
|  | @ -72,5 +74,84 @@ func (e Entry) MarshalText() ([]byte, error) { | |||
| } | ||||
| 
 | ||||
| func (m *Entry) UnmarshalText(in []byte) error { | ||||
| 	re := regexp.MustCompile("(?s)^@begin (.+) - (.+?)[ \n]@") | ||||
| 	match := re.FindSubmatch(in) | ||||
| 	if len(match) == 0 { | ||||
| 		return newParsingError(errors.New("Failed to find title and date")) | ||||
| 	} | ||||
| 
 | ||||
| 	ch := m.getFieldUnarshalChan(in) | ||||
| 
 | ||||
| 	title := bytes.TrimSpace(match[2]) | ||||
| 	if len(title) == 0 { | ||||
| 		return ErrorMissingTitle | ||||
| 	} | ||||
| 	m.Title = string(title) | ||||
| 	date := string(bytes.TrimSpace(match[1])) | ||||
| 	if date == "" { | ||||
| 		return ErrorMissingDate | ||||
| 	} | ||||
| 	d, e := time.Parse(time.RFC3339, date) | ||||
| 	if e != nil { | ||||
| 		d, e = time.Parse(DateFormat, date) | ||||
| 		if e != nil { | ||||
| 			return newParsingError(e) | ||||
| 		} | ||||
| 	} | ||||
| 	m.Date = d | ||||
| 
 | ||||
| 	for meta := range ch { | ||||
| 		m.Fields = append(m.Fields, meta) | ||||
| 	} | ||||
| 
 | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func scanEntry(data []byte, atEOF bool) (advance int, token []byte, err error) { | ||||
| 	if atEOF && len(data) == 0 { | ||||
| 		return 0, nil, nil | ||||
| 	} | ||||
| 	if i := bytes.Index(data, []byte{10, 64}); i > 0 { | ||||
| 		return i + 1, data[0:i], nil | ||||
| 	} | ||||
| 	if atEOF { | ||||
| 		end := []byte{32, 64, 101, 110, 100} | ||||
| 		token = data | ||||
| 		if i := bytes.Index(data, end); i >= 0 { | ||||
| 			token = data[0:i] | ||||
| 		} | ||||
| 		return len(data), token, nil | ||||
| 	} | ||||
| 	// Request more data. | ||||
| 	return 0, nil, nil | ||||
| } | ||||
| 
 | ||||
| func (e *Entry) getFieldUnarshalChan(in []byte) chan Meta { | ||||
| 	size := len(in) / 3 // rough estimation | ||||
| 	ch := make(chan Meta, size) | ||||
| 	var wg sync.WaitGroup | ||||
| 
 | ||||
| 	read := bytes.NewReader(in) | ||||
| 	scan := bufio.NewScanner(read) | ||||
| 	scan.Split(scanEntry) | ||||
| 	scan.Scan() // throw out first line | ||||
| 
 | ||||
| 	// @todo figure out a way to handle json field | ||||
| 	for scan.Scan() { | ||||
| 		wg.Add(1) | ||||
| 		go func(field []byte) { | ||||
| 			defer wg.Done() | ||||
| 			m := new(Meta) | ||||
| 			err := m.UnmarshalText(field) | ||||
| 			if err == nil { | ||||
| 				ch <- *m | ||||
| 			} | ||||
| 		}(scan.Bytes()) | ||||
| 	} | ||||
| 
 | ||||
| 	go func() { | ||||
| 		wg.Wait() | ||||
| 		close(ch) | ||||
| 	}() | ||||
| 	return ch | ||||
| } | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue