Skip to content

Commit

Permalink
Improve u64 support + add other precisions to tutorial/cddl-checker tool
Browse files Browse the repository at this point in the history
To aleviate the pain of working with `int` which involes going through
`BigNum` and such, the tutorial was updated in line with cddl-codegen's
update today to support explicit u32/i32/u64/i64 allowing native JS
numbers to be used in the 32-bit specifications.
  • Loading branch information
rooooooooob committed Sep 15, 2020
1 parent 88b2954 commit 6b946fb
Show file tree
Hide file tree
Showing 4 changed files with 37 additions and 7 deletions.
29 changes: 23 additions & 6 deletions doc/getting-started/metadata.md
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ Upsides:
Downsides:
* Does not support bytes (metdata side), or null/true/false (JSON side) to ensure unambiguous conversions
* Does not support integers beyond signed 32-bits
* Does not support negative integers between `-2^64 + 1` and `-2^63` (serde_json library restriction)
* Structural validation must be done by hand
* Can use more space as string keyed maps are likely to be used more than arrays would be in the CDDL solutions
* Does not support non-string map keys
Expand Down Expand Up @@ -211,10 +211,13 @@ which should give you the library as a package in the `/pkg/` directory.
Once we have imported the library we can then use it as such:
```javascript
const tags = OurMetadataLib.Ints.new();
tags.add(OurMetadataLib.Int.new(0));
tags.add(OurMetadataLib.Int.new(264));
tags.add(OurMetadataLib.Int.new_negative(1024));
tags.add(OurMetadataLib.Int.new(32));
// if we have smaller (32-bit signed) numbers we can construct easier
tags.add(OurMetadataLib.Int.new_i32(0));
// but for bigger numbers we must use BigNum and specify the sign ourselves
tags.add(OurMetadataLib.Int.new(CardanoWasm.Int.from_str("264")));
// and for negative large numbers (here we construct -1024)
tags.add(OurMetadataLib.Int.new_negative(CardanoWasm.Int.from_str("1024")));
tags.add(OurMetadataLib.Int.new_i32(32));
const map = OurMetadataLib.Foo.new("SJKdj34k3jjKFDKfjFUDfdjkfd", "jkfdsufjdk34h3Sdfjdhfduf873", "happy birthday", tags)
let metadata;
try {
Expand All @@ -224,7 +227,7 @@ try {
}
```
likewise you parse the metadat back very simply as:
likewise you can parse the metadata back very simply with:
```javascript
let cddlMetadata;
try {
Expand All @@ -235,6 +238,20 @@ try {
// we can now directly access the fields with cddlMetadata.receiver_id(), etc
```
If we take advantage of the additional primitives not defined in CDDL but defined for `cddl-codegen`, then we can specify precisions of `u32`, `u64`, `i64`, `i32` for specifying 32 or 64 bits instead of just a general purpose `uint`/`nint`/`int`.
If you know your metadata will always be within one of these ranges it can be much more convenient to work with, and if you have signed data this will also make it easier to work with instead of the `Int` class that CDDL `int` might generate, since that is either an up to 64-bit positive or an up to 64 negative numbers.
This is particularly useful here as lists of CDDL primitives can be exposed directly as `Vec<T>` to wasm from rust, but when we have `int` (converts to `Int` struct) or `uint` (converts to `BigNum` struct) a separate structure like that `Ints` one used above is used. Using the 32-bit versions allows direct js `number` conversions to/from wasm.
If we simply change the `tags` field to `tags: [+i32]` our code becomes:
```javascript
// notice how we can directly work with js numbers here now!
// but remember they must fit into a 32-bit number now - no 64-bit numbers like are allowed in the metadata
const tags = [0, 264, -1024, 32];
const map = OurMetadataLib.Foo.new("SJKdj34k3jjKFDKfjFUDfdjkfd", "jkfdsufjdk34h3Sdfjdhfduf873", "happy birthday", tags)
```
and deserializaing likewise is much simpler as `metadata.tags()` will return a JS array or numbers rather than a rust-wasm struct that must be accessed via the wasm boundary.
## Raw Bytes Encoding
Upsides:
Expand Down
6 changes: 5 additions & 1 deletion rust/src/metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -339,7 +339,11 @@ pub fn decode_metadatum_to_json_value(metadatum: &TransactionMetadatum) -> Resul
TransactionMetadatumEnum::MetadataList(arr) => {
Ok(Value::from(arr.0.iter().map(decode_metadatum_to_json_value).collect::<Result<Vec<_>, JsValue>>()?))
},
TransactionMetadatumEnum::Int(x) => Ok(Value::from(i64::try_from(x.0).map_err(|e| JsValue::from_str(&e.to_string()))?)),
TransactionMetadatumEnum::Int(x) => if x.0 >= 0 {
Ok(Value::from(u64::try_from(x.0).map_err(|e| JsValue::from_str(&e.to_string()))?))
} else {
Ok(Value::from(i64::try_from(x.0).map_err(|e| JsValue::from_str(&e.to_string()))?))
},
TransactionMetadatumEnum::Bytes(_) => Err(JsValue::from_str("bytes not allowed in JSON")),
TransactionMetadatumEnum::Text(s) => Ok(Value::from(s.clone())),
}
Expand Down
4 changes: 4 additions & 0 deletions rust/src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,10 @@ impl Int {
Self(-(x.0 as i128))
}

pub fn new_i32(x: i32) -> Self {
Self(x.0 as i128)
}

pub fn is_positive(&self) -> bool {
return self.0 >= 0
}
Expand Down
5 changes: 5 additions & 0 deletions tools/metadata-cddl-checker/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@ fn verify_ident(ident: &Identifier, is_key: bool) -> Result<(), String> {
"tstr" |
"bytes" |
"bstr" => Ok(()),
// these are non-standard types referring to the cddl-codgen tool
"u32" |
"i32" |
"u64" |
"i64" => Ok(()),
// or invalid standard prelude types
"bool" |
"float" |
Expand Down

0 comments on commit 6b946fb

Please sign in to comment.