From: Sergey Matveev Date: Thu, 12 Dec 2024 09:55:15 +0000 (+0300) Subject: More docstrings X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=1b359295e0ea82b28e4b47b19743d1ed2f61b5b100a64d4734da63fe78e8628c;p=keks.git More docstrings --- diff --git a/gyac/atom/dec.go b/gyac/atom/dec.go index 6fccb3f..8f36ad2 100644 --- a/gyac/atom/dec.go +++ b/gyac/atom/dec.go @@ -37,6 +37,8 @@ var ( ErrBadInt = errors.New("bad int value") ) +// Decode a single YAC-encoded atom. Atom means that it does not decode +// full lists, maps, blobs and may return types.EOC. func Decode(buf []byte) (t types.Type, v any, off int, err error) { off = 1 if len(buf) < 1 { diff --git a/gyac/atom/enc.go b/gyac/atom/enc.go index 39c4af0..a6b757b 100644 --- a/gyac/atom/enc.go +++ b/gyac/atom/enc.go @@ -52,14 +52,17 @@ const ( IsUTF8 = 0x40 ) +// Append an encoded EOC atom to the buf. func EOCEncode(buf []byte) []byte { return append(buf, byte(EOC)) } +// Append an encoded NIL atom to the buf. func NILEncode(buf []byte) []byte { return append(buf, byte(NIL)) } +// Append an encoded TRUE/FALSE atom to the buf. func BoolEncode(buf []byte, v bool) []byte { if v { return append(buf, byte(True)) @@ -67,6 +70,7 @@ func BoolEncode(buf []byte, v bool) []byte { return append(buf, byte(False)) } +// Append an encoded UUID atom to the buf. func UUIDEncode(buf []byte, v uuid.UUID) []byte { return append(append(buf, byte(UUID)), v[:]...) } @@ -86,10 +90,13 @@ func atomUintEncode(v uint64) (buf []byte) { return BinEncode(nil, buf) } +// Append an encoded +INT atom to the buf. func UIntEncode(buf []byte, v uint64) []byte { return append(buf, append([]byte{byte(PInt)}, atomUintEncode(v)...)...) } +// Append an encoded -INT atom to the buf if v is negative. +// +INT atom otherwise, same as UIntEncode. func IntEncode(buf []byte, v int64) []byte { if v >= 0 { return UIntEncode(buf, uint64(v)) @@ -98,8 +105,8 @@ func IntEncode(buf []byte, v int64) []byte { atomUintEncode(uint64(-(v+1)))...)...) } +// Append an encoded ±INT atom to the buf. func BigIntEncode(buf []byte, v *big.Int) []byte { - // TODO: fallback to U?IntEncode for small values if v.Cmp(bigIntZero) >= 0 { return append(buf, BinEncode([]byte{byte(PInt)}, v.Bytes())...) } @@ -109,14 +116,21 @@ func BigIntEncode(buf []byte, v *big.Int) []byte { return append(buf, BinEncode([]byte{byte(NInt)}, v.Bytes())...) } +// Append an encoded LIST atom to the buf. +// You have to manually terminate it with EOCEncode. func ListEncode(buf []byte) []byte { return append(buf, byte(List)) } +// Append an encoded MAP atom to the buf. +// You have to manually terminate it with EOCEncode. func MapEncode(buf []byte) []byte { return append(buf, byte(Map)) } +// Append an encoded BLOB atom to the buf. +// You have to manually provide necessary chunks and +// properly terminate it with BinEncode. func BlobEncode(buf []byte, chunkLen int) []byte { l := make([]byte, 9) l[0] = byte(Blob) @@ -148,18 +162,23 @@ func atomStrEncode(buf, data []byte, utf8 bool) []byte { return append(append(append(buf, b), l...), data...) } +// Append an encoded STR atom to the buf. func StrEncode(buf []byte, str string) []byte { return atomStrEncode(buf, []byte(str), true) } +// Append an encoded BIN atom to the buf. func BinEncode(buf, bin []byte) []byte { return atomStrEncode(buf, bin, false) } +// Append an encoded CHUNK atom to the buf. +// That is basically an appended NIL with the chunk value. func ChunkEncode(buf, chunk []byte) []byte { return append(append(buf, byte(NIL)), chunk...) } +// Append an encoded TAI64* atom to the buf. func TAI64Encode(buf, tai []byte) []byte { switch len(tai) { case 8: @@ -173,6 +192,7 @@ func TAI64Encode(buf, tai []byte) []byte { } } +// Append an encoded raw atom's value to the buf. func RawEncode(buf []byte, raw Raw) []byte { return append(append(buf, byte(raw.T)), raw.V...) } diff --git a/gyac/atom/raw.go b/gyac/atom/raw.go index ddc30d8..337bea5 100644 --- a/gyac/atom/raw.go +++ b/gyac/atom/raw.go @@ -1,3 +1,18 @@ +// gyac -- Go YAC encoder implementation +// Copyright (C) 2024-2025 Sergey Matveev +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation, version 3 of the License. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program. If not, see . + package atom import ( @@ -5,6 +20,8 @@ import ( "fmt" ) +// Raw atom storage, keeping the tag T and contents V after it. +// Used for keeping data that can not be represented in native Go types. type Raw struct { V []byte T Type diff --git a/gyac/blob.go b/gyac/blob.go index 1566e21..23e0d38 100644 --- a/gyac/blob.go +++ b/gyac/blob.go @@ -17,6 +17,7 @@ package gyac import "fmt" +// BLOB object, that keeps data splitted on ChunkLen chunks. type Blob struct { Chunks [][]byte ChunkLen int diff --git a/gyac/cmd/test-vector-anys/main.go b/gyac/cmd/test-vector-anys/main.go index ae4bad7..c1713d8 100644 --- a/gyac/cmd/test-vector-anys/main.go +++ b/gyac/cmd/test-vector-anys/main.go @@ -8,6 +8,7 @@ import ( "time" "github.com/google/uuid" + "go.cypherpunks.su/yac/gyac" "go.cypherpunks.su/yac/gyac/atom" ) diff --git a/gyac/cmd/test-vector-manual/main.go b/gyac/cmd/test-vector-manual/main.go index c34e17e..c070c26 100644 --- a/gyac/cmd/test-vector-manual/main.go +++ b/gyac/cmd/test-vector-manual/main.go @@ -9,6 +9,7 @@ import ( "github.com/google/uuid" "go.cypherpunks.su/tai64n/v4" + "go.cypherpunks.su/yac/gyac/atom" ) diff --git a/gyac/dec.go b/gyac/dec.go index a3561d8..de994d6 100644 --- a/gyac/dec.go +++ b/gyac/dec.go @@ -32,6 +32,23 @@ var ( ErrUnexpectedEOC = errors.New("unexpected EOC") ) +// Item is the base object, holding the type and corresponding value. +// Depending on the type, you have to type assert the value. +// - EOC, NIL holds nothing +// - Bool holds bool +// - UUID holds uuid.UUID +// - UInt holds uint64 +// - Int holds negative int64 +// - BigInt holds *big.Int +// - List holds []Item +// - Map holds map[string]Item +// - Blob holds Blob +// - Float (currently) holds atom.Raw +// - TAI64 holds []byte with with the TAI64 in external format. +// Look at its length to determine exact value +// - Bin holds []byte +// - Str holds string +// - Raw holds the atom.Raw type Item struct { V any T types.Type @@ -170,6 +187,7 @@ func decode( return } -func Decode(buf []byte) (item *Item, tail []byte, err error) { +// Decode single YAC-encoded data item. Remaining data will be kept in tail. +func Decode(buf []byte) (item Item, tail []byte, err error) { return decode(buf, true, false, 0) } diff --git a/gyac/doc.go b/gyac/doc.go new file mode 100644 index 0000000..67ebca6 --- /dev/null +++ b/gyac/doc.go @@ -0,0 +1,6 @@ +// YAC (http://www.yac.cypherpunks.su) is yet another binary +// serialisation encoding format. It is aimed to be lightweight in terms +// of CPU, memory, storage and codec implementation size usage. YAC is +// deterministic and streamable. It supports wide range of data types, +// making it able to transparently replace JSON. +package gyac diff --git a/gyac/enc.go b/gyac/enc.go index 92de56a..c9c912d 100644 --- a/gyac/enc.go +++ b/gyac/enc.go @@ -25,6 +25,7 @@ import ( "go.cypherpunks.su/yac/gyac/types" ) +// Encode an item appending to the buf. func (item Item) Encode(buf []byte) []byte { switch item.T { case types.NIL: diff --git a/gyac/fromgo.go b/gyac/fromgo.go index 5ea9bae..f5f61af 100644 --- a/gyac/fromgo.go +++ b/gyac/fromgo.go @@ -44,6 +44,23 @@ func structTagRead(f reflect.StructField) (name string, omit bool) { return } +// Create an Item from native Go type, for its future encoding. +// Allowable types: +// - [*]atom.Raw +// - [*]Blob +// - *big.Int +// - []any +// - []byte -- will be converted to binary string +// - bool +// - int, int8, int16, int32, int64 +// - map[string]any +// - nil +// - string +// - struct -- will be interpreted as map[string]any +// - time.Time -- will be converted either to +// TAI64 (if nanoseconds=0), or TAI64N +// - uint, uint8, uint16, uint32, uint64 +// - uuid.UUID func FromGo(v any) Item { if v == nil { return Item{T: types.NIL} diff --git a/gyac/mapstruct/dec.go b/gyac/mapstruct/dec.go index bcba9ff..5d214f9 100644 --- a/gyac/mapstruct/dec.go +++ b/gyac/mapstruct/dec.go @@ -22,6 +22,8 @@ import ( "go.cypherpunks.su/yac/gyac/types" ) +// Decode YAC-encoded data to the dst structure. +// It will return an error if decoded data is not map. func Decode(dst any, raw []byte) (tail []byte, err error) { var item gyac.Item item, tail, err = gyac.Decode(raw) diff --git a/gyac/mapstruct/map.go b/gyac/mapstruct/map.go index bc3b3a2..ffcd493 100644 --- a/gyac/mapstruct/map.go +++ b/gyac/mapstruct/map.go @@ -19,6 +19,7 @@ import ( "github.com/mitchellh/mapstructure" ) +// Fill up dst structure with the contents taken from the src map. func FromMap(dst any, src map[string]any) error { decoder, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{ Result: dst, TagName: "yac", diff --git a/gyac/sort.go b/gyac/sort.go index 4259644..66f751f 100644 --- a/gyac/sort.go +++ b/gyac/sort.go @@ -1,5 +1,6 @@ package gyac +// Bitewise sorting by length first. type ByLenFirst []string func (a ByLenFirst) Len() int { diff --git a/gyac/togo.go b/gyac/togo.go index 4dc62f9..f0782af 100644 --- a/gyac/togo.go +++ b/gyac/togo.go @@ -25,6 +25,8 @@ import ( "go.cypherpunks.su/yac/gyac/types" ) +// Convert an item to various native Go types, atom.Raw, Blob, uuid.UUID. +// Pay attention that f TAI equals to leap second, then it is converted to Raw. func (item Item) ToGo() any { switch item.T { case types.NIL: