Skip to content

Commit

Permalink
Terminal: switch to termenv library
Browse files Browse the repository at this point in the history
* No need to override stdout/stderr anymore
* Some improvements to transcribe colorizing
* Some ARD fixes

Also upgrade to Go 1.19
  • Loading branch information
tliron committed Aug 17, 2022
1 parent 4ad2fa3 commit ecc9037
Show file tree
Hide file tree
Showing 27 changed files with 355 additions and 273 deletions.
29 changes: 17 additions & 12 deletions ard/cjson.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,18 +20,23 @@ This particular implementation is not designed for performance but rather for
widest compability, relying on Go's built-in JSON support or 3rd-party
implementations compatible with it.
Inspired by: https://docs.mongodb.com/manual/reference/mongodb-Compatible-json/
Inspired by: https://www.mongodb.com/docs/manual/reference/mongodb-extended-json/
*/

var CompatibleJSONIntegerCode = "$ard.integer"
var CompatibleJSONUIntegerCode = "$ard.uinteger"
var CompatibleJSONBytesCode = "$ard.bytes"
var CompatibleJSONMapCode = "$ard.map"
const (
CompatibleJSONIntegerCode = "$ard.integer"
CompatibleJSONUIntegerCode = "$ard.uinteger"
CompatibleJSONBytesCode = "$ard.bytes"
CompatibleJSONMapCode = "$ard.map"
)

func EnsureCompatibleJSON(value Value) Value {
value, _ = Canonicalize(value)
value, _ = ToCompatibleJSON(value)
return value
func EnsureCompatibleJSON(value Value) (Value, error) {
if value_, err := Canonicalize(value); err == nil {
value_, _ = ToCompatibleJSON(value_)
return value_, nil
} else {
return nil, err
}
}

func ToCompatibleJSON(value Value) (Value, bool) {
Expand Down Expand Up @@ -276,15 +281,15 @@ func (self CompatibleJSONMap) MarshalJSON() ([]byte, error) {
func DecodeCompatibleJSONMap(code StringMap) (Map, bool) {
if map_, ok := code[CompatibleJSONMapCode]; ok {
if map__, ok := map_.(List); ok {
r := make(Map)
map___ := make(Map)
for _, entry := range map__ {
if entry_, ok := DecodeCompatibleJSONMapEntry(entry); ok {
r[entry_.Key] = entry_.Value
map___[entry_.Key] = entry_.Value
} else {
return nil, false
}
}
return r, true
return map___, true
}
}
return nil, false
Expand Down
33 changes: 19 additions & 14 deletions ard/reflection.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,9 @@ func NewReflector() *Reflector {

// Fills in Go struct fields from ARD maps
func (self *Reflector) Pack(value Value, packedValuePtr any) error {
compositeValuePtr_ := reflect.ValueOf(packedValuePtr)
if compositeValuePtr_.Kind() == reflect.Pointer {
return self.PackReflect(value, compositeValuePtr_)
packedValuePtr_ := reflect.ValueOf(packedValuePtr)
if packedValuePtr_.Kind() == reflect.Pointer {
return self.PackReflect(value, packedValuePtr_)
} else {
return fmt.Errorf("not a pointer: %T", packedValuePtr)
}
Expand Down Expand Up @@ -107,7 +107,7 @@ func (self *Reflector) PackReflect(value Value, packedValue reflect.Value) error
return fmt.Errorf("not a float: %s", packedType.String())
}

case time.Time: // as-is values
case []byte, time.Time: // as-is values
if packedType == reflect.TypeOf(value_) {
packedValue.Set(reflect.ValueOf(value_))
} else {
Expand Down Expand Up @@ -269,6 +269,11 @@ func (self *Reflector) UnpackReflect(packedValue reflect.Value) (Value, error) {
return packedValue.Interface(), nil

case reflect.Slice:
if packedType.Elem().Kind() == reflect.Uint8 {
// []byte
return packedValue.Interface(), nil
}

length := packedValue.Len()
list := make(List, length)
for index := 0; index < length; index++ {
Expand Down Expand Up @@ -298,13 +303,13 @@ func (self *Reflector) UnpackReflect(packedValue reflect.Value) (Value, error) {
case reflect.Struct:
map_ := make(Map)
for name, field := range self.NewReflectFields(packedType) {
value_ := packedValue.FieldByName(field.Name)
value_ := packedValue.FieldByName(field.name)
if value__, err := self.UnpackReflect(value_); err == nil {
if !field.OmitEmpty || !reflection.IsEmpty(value__) {
if !field.omitEmpty || !reflection.IsEmpty(value__) {
map_[name] = value__
}
} else {
return nil, fmt.Errorf("struct field %q %s", field.Name, err.Error())
return nil, fmt.Errorf("struct field %q %s", field.name, err.Error())
}
}
return map_, nil
Expand Down Expand Up @@ -341,8 +346,8 @@ func (self *Reflector) setStructField(structValue reflect.Value, fieldName strin
//

type ReflectField struct {
Name string
OmitEmpty bool
name string
omitEmpty bool
}

type ReflectFields map[string]ReflectField // ARD name
Expand All @@ -355,7 +360,7 @@ func (self *Reflector) NewReflectFields(type_ reflect.Type) ReflectFields {
reflectFields := make(ReflectFields)

for _, structField := range reflection.GetStructFields(type_) {
reflectField := ReflectField{Name: structField.Name}
reflectField := ReflectField{name: structField.Name}

// Try tags in order
tagged := false
Expand All @@ -366,7 +371,7 @@ func (self *Reflector) NewReflectFields(type_ reflect.Type) ReflectFields {
name := splitTag[0]
if name != "-" {
if (length > 1) && (splitTag[1] == "omitempty") {
reflectField.OmitEmpty = true
reflectField.omitEmpty = true
}
reflectFields[name] = reflectField
}
Expand All @@ -379,9 +384,9 @@ func (self *Reflector) NewReflectFields(type_ reflect.Type) ReflectFields {

if !tagged {
if self.StructFieldNameMapper != nil {
reflectFields[self.StructFieldNameMapper(reflectField.Name)] = reflectField
reflectFields[self.StructFieldNameMapper(reflectField.name)] = reflectField
} else {
reflectFields[reflectField.Name] = reflectField
reflectFields[reflectField.name] = reflectField
}
}
}
Expand All @@ -392,5 +397,5 @@ func (self *Reflector) NewReflectFields(type_ reflect.Type) ReflectFields {
}

func (self ReflectFields) GetField(structValue reflect.Value, name string) reflect.Value {
return structValue.FieldByName(self[name].Name)
return structValue.FieldByName(self[name].name)
}
36 changes: 24 additions & 12 deletions ard/roundtrip.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,16 @@ func Roundtrip(value Value, format string) (Value, error) {
case "yaml":
return RoundtripYAML(value)

case "json":
return RoundtripJSON(value)

case "cjson":
// broken
return RoundtripCompatibleJSON(value)

case "xml", "":
// broken
case "xml":
return RoundtripCompatibleXML(value)

case "cbor":
case "cbor", "":
return RoundtripCBOR(value)

case "messagepack":
Expand All @@ -48,28 +49,39 @@ func RoundtripYAML(value Value) (Value, error) {
}
}

func RoundtripCompatibleJSON(value Value) (Value, error) {
value = EnsureCompatibleJSON(value)
func RoundtripJSON(value Value) (Value, error) {
var writer strings.Builder
encoder := json.NewEncoder(&writer)
if err := encoder.Encode(value); err == nil {
value_, _, err := ReadCompatibleJSON(strings.NewReader(writer.String()), false)
value_, _, err := ReadJSON(strings.NewReader(writer.String()), false)
return value_, err
} else {
return nil, err
}
}

func RoundtripCompatibleJSON(value Value) (Value, error) {
if value_, err := EnsureCompatibleJSON(value); err == nil {
var writer strings.Builder
encoder := json.NewEncoder(&writer)
if err := encoder.Encode(value_); err == nil {
value__, _, err := ReadCompatibleJSON(strings.NewReader(writer.String()), false)
return value__, err
} else {
return nil, err
}
} else {
return nil, err
}
}

func RoundtripCompatibleXML(value Value) (Value, error) {
// Because we don't provide explicit marshalling for XML in the codebase (as we do for
// JSON and YAML) we must canonicalize the data before encoding it
if value, err := Canonicalize(value); err == nil {
value = ToCompatibleXML(value)
if value_, err := EnsureCompatibleXML(value); err == nil {
var writer strings.Builder
if _, err := writer.WriteString(xml.Header); err == nil {
encoder := xml.NewEncoder(&writer)
encoder.Indent("", "")
if err := encoder.Encode(value); err == nil {
if err := encoder.Encode(value_); err == nil {
value_, _, err := ReadCompatibleXML(strings.NewReader(writer.String()), false)
return value_, err
} else {
Expand Down
12 changes: 11 additions & 1 deletion ard/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ const (

// Other schemas: https://yaml.org/spec/1.2/spec.html#id2805770
TypeNull TypeName = "ard.null"
TypeBytes TypeName = "ard.bytes"
TypeTimestamp TypeName = "ard.timestamp"
)

Expand All @@ -45,6 +46,8 @@ func GetTypeName(value Value) TypeName {
return TypeFloat
case nil:
return TypeNull
case []byte:
return TypeBytes
case time.Time:
return TypeTimestamp
default:
Expand All @@ -64,6 +67,7 @@ var TypeZeroes = map[TypeName]Value{
TypeInteger: int(0), // YAML parser returns int
TypeFloat: float64(0.0), // YAML and JSON parsers return float64
TypeNull: nil,
TypeBytes: []byte{},
TypeTimestamp: time.Time{}, // YAML parser returns time.Time
}

Expand All @@ -81,6 +85,7 @@ var TypeValidators = map[TypeName]TypeValidator{
TypeInteger: IsInteger,
TypeFloat: IsFloat,
TypeNull: IsNull,
TypeBytes: IsBytes,
TypeTimestamp: IsTimestamp,
}

Expand Down Expand Up @@ -130,6 +135,11 @@ func IsNull(value Value) bool {
return value == nil
}

func IsBytes(value Value) bool {
_, ok := value.([]byte)
return ok
}

// time.Time
func IsTimestamp(value Value) bool {
_, ok := value.(time.Time)
Expand All @@ -138,7 +148,7 @@ func IsTimestamp(value Value) bool {

func IsPrimitiveType(value Value) bool {
switch value.(type) {
case string, bool, int64, int32, int16, int8, int, uint64, uint32, uint16, uint8, uint, float64, float32, nil, time.Time:
case string, bool, int64, int32, int16, int8, int, uint64, uint32, uint16, uint8, uint, float64, float32, nil, []byte, time.Time:
return true
default:
return false
Expand Down
6 changes: 0 additions & 6 deletions ard/validate.go

This file was deleted.

Loading

0 comments on commit ecc9037

Please sign in to comment.