Skip to content

Commit

Permalink
[utils] add logic for serializing Move value with both type and field…
Browse files Browse the repository at this point in the history
… names

This is useful for viewing Move values as tree-structured data in formats that are likely to be consumed by clients (e.g., json).

Closes: diem#44
  • Loading branch information
sblackshear authored and jsladermanACN committed Feb 8, 2022
1 parent 4f5866b commit 1e5e36c
Show file tree
Hide file tree
Showing 7 changed files with 322 additions and 20 deletions.
2 changes: 1 addition & 1 deletion language/move-binary-format/src/normalized.rs
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,7 @@ impl Struct {
pub fn new(m: &CompiledModule, def: &StructDefinition) -> (Identifier, Self) {
let handle = m.struct_handle_at(def.struct_handle);
let fields = match &def.field_information {
StructFieldInformation::Native => panic!("Can't extract for native struct"),
StructFieldInformation::Native => panic!("Can't extract for native struct"),
StructFieldInformation::Declared(fields) => {
fields.iter().map(|f| Field::new(m, f)).collect()
}
Expand Down
9 changes: 9 additions & 0 deletions language/move-core/types/src/language_storage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,21 @@ pub const CORE_CODE_ADDRESS: AccountAddress = AccountAddress::ONE;

#[derive(Serialize, Deserialize, Debug, PartialEq, Hash, Eq, Clone, PartialOrd, Ord)]
pub enum TypeTag {
#[serde(rename = "bool")]
Bool,
#[serde(rename = "u8")]
U8,
#[serde(rename = "u64")]
U64,
#[serde(rename = "u128")]
U128,
#[serde(rename = "address")]
Address,
#[serde(rename = "signer")]
Signer,
#[serde(rename = "vector")]
Vector(Box<TypeTag>),
#[serde(rename = "struct")]
Struct(StructTag),
}

Expand All @@ -34,6 +42,7 @@ pub struct StructTag {
pub module: Identifier,
pub name: Identifier,
// TODO: rename to "type_args" (or better "ty_args"?)
#[serde(rename = "type_args")]
pub type_params: Vec<TypeTag>,
}

Expand Down
1 change: 1 addition & 0 deletions language/move-core/types/src/unit_tests/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@

mod identifier_test;
mod language_storage_test;
mod value_test;
103 changes: 103 additions & 0 deletions language/move-core/types/src/unit_tests/value_test.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
// Copyright (c) The Diem Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::{
account_address::AccountAddress,
ident_str,
identifier::Identifier,
language_storage::{StructTag, TypeTag},
value::{MoveStruct, MoveValue},
};
use serde_json::json;

#[test]
fn struct_deserialization() {
let struct_type = StructTag {
address: AccountAddress::ZERO,
name: ident_str!("MyStruct").to_owned(),
module: ident_str!("MyModule").to_owned(),
type_params: vec![],
};
let values = vec![MoveValue::U64(7), MoveValue::Bool(true)];
let fields = vec![ident_str!("f").to_owned(), ident_str!("g").to_owned()];
let field_values: Vec<(Identifier, MoveValue)> =
fields.into_iter().zip(values.clone()).collect();

// test each deserialization scheme
let runtime_value = MoveStruct::Runtime(values);
assert_eq!(
serde_json::to_value(&runtime_value).unwrap(),
json!([7, true])
);

let fielded_value = MoveStruct::WithFields(field_values.clone());
assert_eq!(
serde_json::to_value(&fielded_value).unwrap(),
json!({ "f": 7, "g": true })
);

let typed_value = MoveStruct::with_types(struct_type, field_values);
assert_eq!(
serde_json::to_value(&typed_value).unwrap(),
json!({
"fields": { "f": 7, "g": true },
"type": "0x0::MyModule::MyStruct"
}
)
);
}

#[test]
fn nested_typed_struct_deserialization() {
let struct_type = StructTag {
address: AccountAddress::ZERO,
name: ident_str!("MyStruct").to_owned(),
module: ident_str!("MyModule").to_owned(),
type_params: vec![],
};
let nested_struct_type = StructTag {
address: AccountAddress::ZERO,
name: ident_str!("NestedStruct").to_owned(),
module: ident_str!("NestedModule").to_owned(),
type_params: vec![TypeTag::U8],
};

// test each deserialization scheme
let nested_runtime_struct = MoveValue::Struct(MoveStruct::Runtime(vec![MoveValue::U64(7)]));
let runtime_value = MoveStruct::Runtime(vec![nested_runtime_struct]);
assert_eq!(serde_json::to_value(&runtime_value).unwrap(), json!([[7]]));

let nested_fielded_struct = MoveValue::Struct(MoveStruct::with_fields(vec![(
ident_str!("f").to_owned(),
MoveValue::U64(7),
)]));
let fielded_value = MoveStruct::with_fields(vec![(
ident_str!("inner").to_owned(),
nested_fielded_struct,
)]);
assert_eq!(
serde_json::to_value(&fielded_value).unwrap(),
json!({ "inner": { "f": 7 } })
);

let nested_typed_struct = MoveValue::Struct(MoveStruct::with_types(
nested_struct_type,
vec![(ident_str!("f").to_owned(), MoveValue::U64(7))],
));
let typed_value = MoveStruct::with_types(
struct_type,
vec![(ident_str!("inner").to_owned(), nested_typed_struct)],
);
assert_eq!(
serde_json::to_value(&typed_value).unwrap(),
json!({
"fields": {
"inner": {
"fields": { "f": 7},
"type": "0x0::NestedModule::NestedStruct<u8>",
}
},
"type": "0x0::MyModule::MyStruct"
})
);
}
Loading

0 comments on commit 1e5e36c

Please sign in to comment.