// Package postcard encodes and decodes the Rust postcard wire format.
package postcard import ( ) // Marshaler is implemented by values with a custom postcard representation. type Marshaler interface { MarshalPostcard() ([]byte, error) } // EncoderTo is implemented by values that encode themselves to e. type EncoderTo interface { EncodePostcard(*Encoder) error } // DecoderFrom is implemented by values that decode themselves from d. type DecoderFrom interface { DecodePostcard(*Decoder) error } var ( // ErrTrailingBytes is returned when Unmarshal does not consume all input. ErrTrailingBytes = errors.New("postcard: trailing bytes") errShort = errors.New("postcard: truncated input") ) // Marshal encodes v in postcard format. func ( any) ([]byte, error) { var Encoder if := .value(reflect.ValueOf()); != nil { return nil, } return .b, nil } // Unmarshal decodes postcard data into v. func ( []byte, any) error { if == nil { return errors.New("postcard: nil target") } := Decoder{b: } := reflect.ValueOf() if .Kind() != reflect.Pointer || .IsNil() { return errors.New("postcard: target must be non-nil pointer") } if := .value(.Elem()); != nil { return } if .off != len(.b) { return ErrTrailingBytes } return nil } // Encoder incrementally encodes postcard values. type Encoder struct { b []byte } // Encode appends v to e. func ( *Encoder) ( any) error { return .value(reflect.ValueOf()) } // Bytes returns a copy of the encoded bytes. func ( *Encoder) () []byte { return append([]byte(nil), .b...) } // Uint appends v as a postcard unsigned integer. func ( *Encoder) ( uint64) { .b = appendVarint(.b, ) } // Int appends v as a postcard signed integer. func ( *Encoder) ( int64) { .b = appendVarint(.b, zigzag()) } // Bool appends v as a postcard bool. func ( *Encoder) ( bool) { if { .b = append(.b, 1) } else { .b = append(.b, 0) } } // BytesValue appends b as a postcard byte sequence. func ( *Encoder) ( []byte) { .b = appendVarint(.b, uint64(len())) .b = append(.b, ...) } // RawBytes appends b without a length prefix. func ( *Encoder) ( []byte) { .b = append(.b, ...) } // String appends s as a postcard string. func ( *Encoder) ( string) { .BytesValue([]byte()) } func ( *Encoder) ( reflect.Value) error { if !.IsValid() { return errors.New("postcard: invalid value") } if .Kind() == reflect.Interface && !.IsNil() { = .Elem() } if .CanInterface() { if , := .Interface().(Marshaler); { , := .MarshalPostcard() if != nil { return } .b = append(.b, ...) return nil } if , := .Interface().(EncoderTo); { return .EncodePostcard() } if , := .Interface().(encoding.TextMarshaler); && .Kind() == reflect.String { , := .MarshalText() if != nil { return } return .bytes() } } switch .Kind() { case reflect.Pointer: if .IsNil() { .b = append(.b, 0) return nil } .b = append(.b, 1) return .(.Elem()) case reflect.Bool: .Bool(.Bool()) case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: .Uint(.Uint()) case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: .Int(.Int()) case reflect.String: return .bytes([]byte(.String())) case reflect.Array: if .Type().Elem().Kind() == reflect.Uint8 { for := 0; < .Len(); ++ { .b = append(.b, byte(.Index().Uint())) } return nil } for := 0; < .Len(); ++ { if := .(.Index()); != nil { return } } case reflect.Slice: if .IsNil() { .b = appendVarint(.b, 0) return nil } .b = appendVarint(.b, uint64(.Len())) if .Type().Elem().Kind() == reflect.Uint8 { .b = append(.b, .Bytes()...) return nil } for := 0; < .Len(); ++ { if := .(.Index()); != nil { return } } case reflect.Struct: := .Type() for := 0; < .NumField(); ++ { if .Field().PkgPath != "" { continue } if := .(.Field()); != nil { return } } default: return fmt.Errorf("postcard: unsupported type %s", .Type()) } return nil } func ( *Encoder) ( []byte) error { .b = appendVarint(.b, uint64(len())) .b = append(.b, ...) return nil } // Decoder incrementally decodes postcard values. type Decoder struct { b []byte off int } // NewDecoder returns a decoder reading b. func ( []byte) *Decoder { return &Decoder{b: } } // Decode decodes the next postcard value into v. func ( *Decoder) ( any) error { if == nil { return errors.New("postcard: nil target") } := reflect.ValueOf() if .Kind() != reflect.Pointer || .IsNil() { return errors.New("postcard: target must be non-nil pointer") } return .value(.Elem()) } // Done reports whether d consumed all input. func ( *Decoder) () bool { return .off == len(.b) } // Uint decodes a postcard unsigned integer. func ( *Decoder) () (uint64, error) { return .varint() } // Int decodes a postcard signed integer. func ( *Decoder) () (int64, error) { , := .varint() if != nil { return 0, } return unzigzag(), nil } // Bool decodes a postcard bool. func ( *Decoder) () (bool, error) { , := .byte() if != nil { return false, } switch { case 0: return false, nil case 1: return true, nil default: return false, fmt.Errorf("postcard: invalid bool %d", ) } } // BytesValue decodes a postcard byte sequence. func ( *Decoder) () ([]byte, error) { return .bytes() } // RawBytes decodes n bytes without a length prefix. func ( *Decoder) ( int) ([]byte, error) { if < 0 || .off+ > len(.b) { return nil, errShort } := .b[.off : .off+] .off += return , nil } // String decodes a postcard string. func ( *Decoder) () (string, error) { , := .bytes() if != nil { return "", } if !utf8.Valid() { return "", fmt.Errorf("postcard: invalid utf-8 string") } return string(), nil } func ( *Decoder) ( reflect.Value) error { if !.CanSet() { return fmt.Errorf("postcard: cannot set %s", .Type()) } if .CanAddr() { if , := .Addr().Interface().(DecoderFrom); { return .DecodePostcard() } } switch .Kind() { case reflect.Pointer: , := .option() if != nil { return } if ! { .SetZero() return nil } if .IsNil() { .Set(reflect.New(.Type().Elem())) } return .(.Elem()) case reflect.Bool: , := .Bool() if != nil { return } .SetBool() case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: , := .varint() if != nil { return } if .OverflowUint() { return fmt.Errorf("postcard: %d overflows %s", , .Type()) } .SetUint() case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: , := .Int() if != nil { return } if .OverflowInt() { return fmt.Errorf("postcard: %d overflows %s", , .Type()) } .SetInt() case reflect.String: , := .String() if != nil { return } .SetString() case reflect.Array: if .Type().Elem().Kind() == reflect.Uint8 { if .off+.Len() > len(.b) { return errShort } reflect.Copy(, reflect.ValueOf(.b[.off:.off+.Len()])) .off += .Len() return nil } for := 0; < .Len(); ++ { if := .(.Index()); != nil { return } } case reflect.Slice: , := .varint() if != nil { return } if > uint64(math.MaxInt) { return fmt.Errorf("postcard: sequence too large") } if > uint64(len(.b)-.off) { return errShort } := reflect.MakeSlice(.Type(), int(), int()) if .Type().Elem().Kind() == reflect.Uint8 { reflect.Copy(, reflect.ValueOf(.b[.off:.off+int()])) .off += int() .Set() return nil } for := 0; < int(); ++ { if := .(.Index()); != nil { return } } .Set() case reflect.Struct: := .Type() for := 0; < .NumField(); ++ { if .Field().PkgPath != "" { continue } if := .(.Field()); != nil { return } } default: return fmt.Errorf("postcard: unsupported type %s", .Type()) } return nil } func ( *Decoder) () (byte, error) { if .off >= len(.b) { return 0, errShort } := .b[.off] .off++ return , nil } func ( *Decoder) () ([]byte, error) { , := .varint() if != nil { return nil, } if > uint64(len(.b)-.off) { return nil, errShort } := .b[.off : .off+int()] .off += int() return , nil } func ( *Decoder) () (bool, error) { , := .byte() if != nil { return false, } switch { case 0: return false, nil case 1: return true, nil default: return false, fmt.Errorf("postcard: invalid option %d", ) } } func ( *Decoder) () (uint64, error) { , , := readVarint(.b[.off:]) if != nil { return 0, } .off += return , nil } func appendVarint( []byte, uint64) []byte { for >= 0x80 { = append(, byte()|0x80) >>= 7 } return append(, byte()) } func readVarint( []byte) (uint64, int, error) { var uint64 for := 0; < len(); ++ { if >= 10 { break } := [] if == 9 && > 1 { return 0, 0, fmt.Errorf("postcard: varint overflow") } |= uint64(&0x7f) << (7 * ) if < 0x80 { return , + 1, nil } } return 0, 0, errShort } func zigzag( int64) uint64 { return uint64(<<1) ^ uint64(>>63) } func unzigzag( uint64) int64 { return int64(>>1) ^ -int64(&1) }