-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
add a "front end" for Marshal/Unmarshal
- Loading branch information
Showing
2 changed files
with
97 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
package tell | ||
|
||
import ( | ||
"bytes" | ||
"errors" | ||
"fmt" | ||
r "reflect" | ||
|
||
"github.com/ionous/tell/decode" | ||
"github.com/ionous/tell/encode" | ||
"github.com/ionous/tell/maps/stdmap" | ||
) | ||
|
||
// Marshal returns a tell document representing the passed value. | ||
// | ||
// It traverses the passed type recursively to produce tell data. | ||
// If a value implements encode.Mapper or encode.Sequencer, | ||
// Marshal will use their iterators to serialize their contents. | ||
// | ||
// Otherwise, Marshal() uses the following rules: | ||
// | ||
// Boolean values are encoded as either 'true' or 'false'. | ||
// | ||
// Integer and floating point values are encoded as per go's | ||
// strconv.FormatInt, strconv.FormatUnit, strconv.FormatFloat | ||
// except int16 and uint16 are encoded as hex values starting with '0x'. | ||
// NaN, infinities, and complex numbers will return an error. | ||
// | ||
// Strings are encoded as per strconv.Quote | ||
// | ||
// Arrays and slice values are encoded as tell sequences. | ||
// []byte is not handled in any special way. ( fix? ) | ||
// | ||
// Maps with string keys are encoded as tell mappings; sorted by string. | ||
// other key types return an error. | ||
// | ||
// Pointers and interface values are encoded in place as the value they represent. | ||
// Cyclic data is not handled and will never return. ( fix? ) | ||
// | ||
// Any other types will error ( ie. functions, channels, and structs ) | ||
// | ||
func Marshal(v any) (ret []byte, err error) { | ||
return encode.Encode(v) | ||
} | ||
|
||
// Unmarshal from a tell formatted document and store the result | ||
// into the value pointed to by pv. | ||
// | ||
// Permissible values include: | ||
// bool, floating point, signed and unsigned integers, maps and slices. | ||
// | ||
// For more flexibility, see package decode | ||
// | ||
func Unmarshal(in []byte, pv any) (err error) { | ||
doc := decode.NewDocument(stdmap.Builder, decode.DiscardComments) | ||
if res, e := doc.ReadDoc(bytes.NewReader(in)); e != nil { | ||
err = e | ||
} else { | ||
res, out := r.ValueOf(res.Content), r.ValueOf(pv) | ||
if out.Kind() != r.Pointer { | ||
err = errors.New("expected a pointer") | ||
} else if out := out.Elem(); !out.CanSet() { | ||
err = errors.New("expected a settable value") | ||
} else { | ||
if rt, ot := res.Type(), out.Type(); rt.AssignableTo(ot) { | ||
out.Set(res) | ||
} else if res.CanConvert(ot) { | ||
out.Set(res.Convert(ot)) | ||
} else { | ||
fmt.Errorf("result of %q cant be written to a pointer of %q", rt, ot) | ||
} | ||
} | ||
} | ||
return | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
package tell | ||
|
||
import "testing" | ||
|
||
// minimal testing of the simplified Marshal function. | ||
// ( more extensive testing of decode exists in TestFiles and package decode ) | ||
func TestUnmarshal(t *testing.T) { | ||
var b bool | ||
if e := Unmarshal([]byte(`true`), &b); e != nil { | ||
t.Fatal(e) | ||
} else if !b { | ||
t.Fatal("expected true") | ||
} | ||
var m map[string]any | ||
if e := Unmarshal([]byte(`hello: "there"`), &m); e != nil { | ||
t.Fatal(e) | ||
} else if hello, ok := m["hello:"]; !ok { | ||
t.Fatal("expected key") | ||
} else if hello != "there" { | ||
t.Fatal("expected value") | ||
} | ||
} |