Implement integer source units and chunk payloads
This commit is contained in:
@@ -11,9 +11,8 @@ import (
|
||||
)
|
||||
|
||||
type UnitRef struct {
|
||||
value string
|
||||
value int
|
||||
fromNumber bool
|
||||
number int
|
||||
}
|
||||
|
||||
type SourceRefResponse struct {
|
||||
@@ -23,19 +22,22 @@ type SourceRefResponse struct {
|
||||
}
|
||||
|
||||
func UnitRefFromString(value string) UnitRef {
|
||||
return UnitRef{value: value}
|
||||
parsed, _ := parseUnitRefNumber(value)
|
||||
return UnitRef{value: parsed}
|
||||
}
|
||||
|
||||
func UnitRefFromInt(value int) UnitRef {
|
||||
return UnitRef{
|
||||
value: strconv.Itoa(value),
|
||||
value: value,
|
||||
fromNumber: true,
|
||||
number: value,
|
||||
}
|
||||
}
|
||||
|
||||
func (ref UnitRef) String() string {
|
||||
return ref.value
|
||||
if ref.value == 0 {
|
||||
return ""
|
||||
}
|
||||
return strconv.Itoa(ref.value)
|
||||
}
|
||||
|
||||
func (ref *UnitRef) UnmarshalJSON(raw []byte) error {
|
||||
@@ -48,13 +50,17 @@ func (ref *UnitRef) UnmarshalJSON(raw []byte) error {
|
||||
if err := json.Unmarshal(raw, &value); err != nil {
|
||||
return err
|
||||
}
|
||||
*ref = UnitRefFromString(value)
|
||||
number, err := parseUnitRefNumber(value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*ref = UnitRef{value: number}
|
||||
return nil
|
||||
}
|
||||
|
||||
number, err := strconv.Atoi(string(raw))
|
||||
number, err := parseUnitRefNumber(string(raw))
|
||||
if err != nil {
|
||||
return fmt.Errorf("unit ref must be a string or integer")
|
||||
return err
|
||||
}
|
||||
*ref = UnitRefFromInt(number)
|
||||
return nil
|
||||
@@ -62,72 +68,47 @@ func (ref *UnitRef) UnmarshalJSON(raw []byte) error {
|
||||
|
||||
func (ref UnitRef) MarshalJSON() ([]byte, error) {
|
||||
if ref.fromNumber {
|
||||
return []byte(strconv.Itoa(ref.number)), nil
|
||||
return []byte(strconv.Itoa(ref.value)), nil
|
||||
}
|
||||
return json.Marshal(ref.value)
|
||||
return json.Marshal(ref.String())
|
||||
}
|
||||
|
||||
func ResolveUnitID(doc *source.SourceDocument, field string, ref UnitRef) (string, error) {
|
||||
value := strings.TrimSpace(ref.value)
|
||||
if value == "" {
|
||||
return "", fmt.Errorf("%s must not be empty", field)
|
||||
func ResolveUnitID(doc *source.SourceDocument, field string, ref UnitRef) (int, error) {
|
||||
if ref.value <= 0 {
|
||||
return 0, fmt.Errorf("%s must be positive", field)
|
||||
}
|
||||
if id, ok := canonicalUnitID(doc, value); ok {
|
||||
return id, nil
|
||||
if _, ok := source.UnitIndex(doc, ref.value); !ok {
|
||||
return 0, fmt.Errorf("%s %d was not found", field, ref.value)
|
||||
}
|
||||
if number, ok := unitNumber(value); ok {
|
||||
if id, ok := unitIDByNumber(doc, number); ok {
|
||||
return id, nil
|
||||
}
|
||||
return "", fmt.Errorf("%s %d was not found as a source-unit ID or 1-based unit number", field, number)
|
||||
}
|
||||
return "", fmt.Errorf("%s %q was not found", field, value)
|
||||
return ref.value, nil
|
||||
}
|
||||
|
||||
func SourceRefCandidate(doc *source.SourceDocument, ref SourceRefResponse) source.SourceRef {
|
||||
return source.SourceRef{
|
||||
SourceID: strings.TrimSpace(ref.SourceID),
|
||||
StartUnitID: unitIDCandidate(doc, ref.StartUnitID),
|
||||
EndUnitID: unitIDCandidate(doc, ref.EndUnitID),
|
||||
StartUnitID: unitIDCandidate(ref.StartUnitID),
|
||||
EndUnitID: unitIDCandidate(ref.EndUnitID),
|
||||
}
|
||||
}
|
||||
|
||||
func unitIDCandidate(doc *source.SourceDocument, ref UnitRef) string {
|
||||
value := strings.TrimSpace(ref.value)
|
||||
if id, ok := canonicalUnitID(doc, value); ok {
|
||||
return id
|
||||
}
|
||||
if number, ok := unitNumber(value); ok {
|
||||
if id, ok := unitIDByNumber(doc, number); ok {
|
||||
return id
|
||||
}
|
||||
}
|
||||
return value
|
||||
func unitIDCandidate(ref UnitRef) int {
|
||||
return ref.value
|
||||
}
|
||||
|
||||
func canonicalUnitID(doc *source.SourceDocument, value string) (string, bool) {
|
||||
if doc == nil {
|
||||
return "", false
|
||||
func parseUnitRefNumber(value string) (int, error) {
|
||||
trimmed := strings.TrimSpace(value)
|
||||
if trimmed == "" {
|
||||
return 0, fmt.Errorf("unit ref must not be empty")
|
||||
}
|
||||
for _, unit := range doc.Units {
|
||||
if unit.ID == value {
|
||||
return unit.ID, true
|
||||
}
|
||||
if trimmed != value {
|
||||
return 0, fmt.Errorf("unit ref must not contain leading or trailing whitespace")
|
||||
}
|
||||
return "", false
|
||||
}
|
||||
|
||||
func unitIDByNumber(doc *source.SourceDocument, number int) (string, bool) {
|
||||
if doc == nil || number < 1 || number > len(doc.Units) {
|
||||
return "", false
|
||||
}
|
||||
return doc.Units[number-1].ID, true
|
||||
}
|
||||
|
||||
func unitNumber(value string) (int, bool) {
|
||||
number, err := strconv.Atoi(value)
|
||||
if err != nil {
|
||||
return 0, false
|
||||
return 0, fmt.Errorf("unit ref must be an integer")
|
||||
}
|
||||
return number, true
|
||||
if number <= 0 {
|
||||
return 0, fmt.Errorf("unit ref must be positive")
|
||||
}
|
||||
return number, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user