Skip to content
This repository has been archived by the owner on Nov 23, 2022. It is now read-only.

Commit

Permalink
Add decode values endpoint.
Browse files Browse the repository at this point in the history
  • Loading branch information
q-uint committed Feb 7, 2022
1 parent a3480d0 commit 95cecca
Show file tree
Hide file tree
Showing 2 changed files with 108 additions and 69 deletions.
51 changes: 33 additions & 18 deletions candid.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,20 +13,34 @@ import (
"github.com/di-wu/parser/ast"
)

// ParseDID parses the given raw .did files and returns the Program that is defined in it.
func ParseDID(raw []byte) (did.Description, error) {
p, err := ast.New(raw)
func DecodeValue(value []byte) (string, error) {
types, values, err := idl.Decode(value)
if err != nil {
return did.Description{}, err
return "", err
}
n, err := candid.Prog(p)
if len(types) != 1 || len(values) != 1 {
return "", fmt.Errorf("can not decode: %x", value)
}
s, err := valueToString(types[0], values[0])
if err != nil {
return did.Description{}, err
return "", err
}
if _, err := p.Expect(parser.EOD); err != nil {
return did.Description{}, err
return fmt.Sprintf("(%s)", s), nil
}

func DecodeValues(types []idl.Type, values []interface{}) (string, error) {
var ss []string
if len(types) != len(values) {
return "", fmt.Errorf("unequal length")
}
return did.ConvertDescription(n), nil
for i := range types {
s, err := valueToString(types[i], values[i])
if err != nil {
return "", err
}
ss = append(ss, s)
}
return fmt.Sprintf("(%s)", strings.Join(ss, "; ")), nil
}

func EncodeValue(value string) ([]byte, error) {
Expand All @@ -48,19 +62,20 @@ func EncodeValue(value string) ([]byte, error) {
return idl.Encode(types, args)
}

func DecodeValue(value []byte) (string, error) {
types, args, err := idl.Decode(value)
// ParseDID parses the given raw .did files and returns the Program that is defined in it.
func ParseDID(raw []byte) (did.Description, error) {
p, err := ast.New(raw)
if err != nil {
return "", err
}
if len(types) != 1 || len(args) != 1 {
return "", fmt.Errorf("can not decode: %x", value)
return did.Description{}, err
}
s, err := valueToString(types[0], args[0])
n, err := candid.Prog(p)
if err != nil {
return "", err
return did.Description{}, err
}
return fmt.Sprintf("(%s)", s), nil
if _, err := p.Expect(parser.EOD); err != nil {
return did.Description{}, err
}
return did.ConvertDescription(n), nil
}

func valueToString(typ idl.Type, value interface{}) (string, error) {
Expand Down
126 changes: 75 additions & 51 deletions candid_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,20 @@ import (
"encoding/hex"
"fmt"
"io/ioutil"
"math/big"
"testing"

"github.com/aviate-labs/candid-go"
"github.com/aviate-labs/candid-go/idl"
)

func ExampleEncodeValue() {
e, _ := candid.EncodeValue("0")
fmt.Printf("%x\n", e)
// Output:
// 4449444c00017c00
}

func ExampleParseDID() {
raw, _ := ioutil.ReadFile("testdata/counter.did")
p, _ := candid.ParseDID(raw)
Expand All @@ -19,117 +28,132 @@ func ExampleParseDID() {
// }
}

func ExampleEncodeValue() {
e, _ := candid.EncodeValue("0")
fmt.Printf("%x\n", e)
// Output:
// 4449444c00017c00
}

func TestEncodeValue(t *testing.T) {
func TestDecodeValue(t *testing.T) {
for _, test := range []struct {
value string
encoded string
}{
{"opt null", "4449444c016e7f010000"},
{"opt 0", "4449444c016e7c01000100"},
{"(opt null)", "4449444c016e7f010000"},
{"(opt 0)", "4449444c016e7c01000100"},

{"0", "4449444c00017c00"},
{"(0)", "4449444c00017c00"},
{"(0 : nat)", "4449444c00017d00"},
{"(0 : nat8)", "4449444c00017b00"},
{"(0 : nat16)", "4449444c00017a0000"},
{"(0 : nat32)", "4449444c00017900000000"},
{"(0 : nat64)", "4449444c0001780000000000000000"},
{"(0 : int)", "4449444c00017c00"},
{"(0)", "4449444c00017c00"},
{"(0 : int8)", "4449444c00017700"},
{"(0 : int16)", "4449444c0001760000"},
{"(0 : int32)", "4449444c00017500000000"},
{"(0 : int64)", "4449444c0001740000000000000000"},

{"0.0", "4449444c0001720000000000000000"},
{"(0 : float32)", "4449444c00017300000000"},
{"(0.0 : float32)", "4449444c00017300000000"},
{"(0 : float64)", "4449444c0001720000000000000000"},
{"(0.0 : float64)", "4449444c0001720000000000000000"},
{"(1 : float64)", "4449444c000172000000000000f03f"},

{"true", "4449444c00017e01"},
{"(false : bool)", "4449444c00017e00"},
{"(true)", "4449444c00017e01"},
{"(false)", "4449444c00017e00"},

{"(null)", "4449444c00017f"},

{"\"\"", "4449444c00017100"},
{"\"quint\"", "4449444c000171057175696e74"},
{"(\"\")", "4449444c00017100"},
{"(\"quint\")", "4449444c000171057175696e74"},

{"record {}", "4449444c016c000100"},
{"record {foo = \"baz\"; bar = 42}", "4449444c016c02d3e3aa027c868eb7027101002a0362617a"},
{"(record {})", "4449444c016c000100"},
{"(record { 4895187 = 42; 5097222 = \"baz\" })", "4449444c016c02d3e3aa027c868eb7027101002a0362617a"},

{"variant { ok }", "4449444c016b019cc2017f010000"},
{"variant { err = \"oops...\" }", "4449444c016b01e58eb40271010000076f6f70732e2e2e"},
{"(variant { 24860 })", "4449444c016b019cc2017f010000"},
{"(variant { 5048165 = \"oops...\" })", "4449444c016b01e58eb40271010000076f6f70732e2e2e"},

{"vec {}", "4449444c016d7f010000"},
{"vec { 0; }", "4449444c016d7c01000100"},
{"(vec {})", "4449444c016d7f010000"},
{"(vec { 0 })", "4449444c016d7c01000100"},
} {
e, err := candid.EncodeValue(test.value)
e, err := hex.DecodeString(test.encoded)
if err != nil {
t.Fatal(err)
}
if e := fmt.Sprintf("%x", e); e != test.encoded {
t.Error(test, e)
d, err := candid.DecodeValue(e)
if err != nil {
t.Fatal(err)
}
if d != test.value {
t.Error(test, d)
}
}
}

func TestDecodeValue(t *testing.T) {
func TestDecodeValues(t *testing.T) {
for _, test := range []struct {
value string
types []idl.Type
values []interface{}
}{
{
value: "(0 : nat)",
types: []idl.Type{new((idl.Nat))},
values: []interface{}{new(big.Int)},
},
} {
d, err := candid.DecodeValues(test.types, test.values)
if err != nil {
t.Fatal(err)
}
if d != test.value {
t.Error(test, d)
}
}
}

func TestEncodeValue(t *testing.T) {
for _, test := range []struct {
value string
encoded string
}{
{"(opt null)", "4449444c016e7f010000"},
{"(opt 0)", "4449444c016e7c01000100"},
{"opt null", "4449444c016e7f010000"},
{"opt 0", "4449444c016e7c01000100"},

{"0", "4449444c00017c00"},
{"(0)", "4449444c00017c00"},
{"(0 : nat)", "4449444c00017d00"},
{"(0 : nat8)", "4449444c00017b00"},
{"(0 : nat16)", "4449444c00017a0000"},
{"(0 : nat32)", "4449444c00017900000000"},
{"(0 : nat64)", "4449444c0001780000000000000000"},
{"(0)", "4449444c00017c00"},
{"(0 : int)", "4449444c00017c00"},
{"(0 : int8)", "4449444c00017700"},
{"(0 : int16)", "4449444c0001760000"},
{"(0 : int32)", "4449444c00017500000000"},
{"(0 : int64)", "4449444c0001740000000000000000"},

{"0.0", "4449444c0001720000000000000000"},
{"(0 : float32)", "4449444c00017300000000"},
{"(0.0 : float32)", "4449444c00017300000000"},
{"(0 : float64)", "4449444c0001720000000000000000"},
{"(1 : float64)", "4449444c000172000000000000f03f"},
{"(0.0 : float64)", "4449444c0001720000000000000000"},

{"(true)", "4449444c00017e01"},
{"(false)", "4449444c00017e00"},
{"true", "4449444c00017e01"},
{"(false : bool)", "4449444c00017e00"},

{"(null)", "4449444c00017f"},

{"(\"\")", "4449444c00017100"},
{"(\"quint\")", "4449444c000171057175696e74"},
{"\"\"", "4449444c00017100"},
{"\"quint\"", "4449444c000171057175696e74"},

{"(record {})", "4449444c016c000100"},
{"(record { 4895187 = 42; 5097222 = \"baz\" })", "4449444c016c02d3e3aa027c868eb7027101002a0362617a"},
{"record {}", "4449444c016c000100"},
{"record {foo = \"baz\"; bar = 42}", "4449444c016c02d3e3aa027c868eb7027101002a0362617a"},

{"(variant { 24860 })", "4449444c016b019cc2017f010000"},
{"(variant { 5048165 = \"oops...\" })", "4449444c016b01e58eb40271010000076f6f70732e2e2e"},
{"variant { ok }", "4449444c016b019cc2017f010000"},
{"variant { err = \"oops...\" }", "4449444c016b01e58eb40271010000076f6f70732e2e2e"},

{"(vec {})", "4449444c016d7f010000"},
{"(vec { 0 })", "4449444c016d7c01000100"},
{"vec {}", "4449444c016d7f010000"},
{"vec { 0; }", "4449444c016d7c01000100"},
} {
e, err := hex.DecodeString(test.encoded)
if err != nil {
t.Fatal(err)
}
d, err := candid.DecodeValue(e)
e, err := candid.EncodeValue(test.value)
if err != nil {
t.Fatal(err)
}
if d != test.value {
t.Error(test, d)
if e := fmt.Sprintf("%x", e); e != test.encoded {
t.Error(test, e)
}
}
}

0 comments on commit 95cecca

Please sign in to comment.