Skip to content

Commit d4b03a1

Browse files
authored
feat: impl json object (#128)
* impl json object * add test and fix clippy * fmt * add unmarshal json value * updat ecomments * rollback shared libraries * fix to return error instead of unreachable
1 parent 44a7cff commit d4b03a1

File tree

17 files changed

+501
-46
lines changed

17 files changed

+501
-46
lines changed

crates/e2e-move-tests/src/tests/args.rs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -814,10 +814,7 @@ fn biguint_bigdecimal() {
814814
vec![acc],
815815
str::parse(entry).unwrap(),
816816
vec![],
817-
vec![
818-
r#""100""#.to_string(),
819-
r#""100""#.to_string(),
820-
],
817+
vec![r#""100""#.to_string(), r#""100""#.to_string()],
821818
)
822819
.unwrap();
823820

crates/e2e-move-tests/src/tests/move_unit.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,17 @@
44

55
use crate::test_utils::mock_chain::{BlankAPIImpl, BlankTableViewImpl};
66

7-
use initia_move_gas::{InitiaGasParameters, InitialGasSchedule, MiscGasParameters, NativeGasParameters};
7+
use initia_move_compiler::unit_test_factory::InitiaUnitTestFactory;
8+
use initia_move_gas::{
9+
InitiaGasParameters, InitialGasSchedule, MiscGasParameters, NativeGasParameters,
10+
};
811
use initia_move_natives::{
912
account::NativeAccountContext, all_natives, block::NativeBlockContext, code::NativeCodeContext,
1013
cosmos::NativeCosmosContext, event::NativeEventContext, oracle::NativeOracleContext,
1114
query::NativeQueryContext, staking::NativeStakingContext, table::NativeTableContext,
1215
transaction_context::NativeTransactionContext,
1316
};
1417
use initia_move_types::metadata;
15-
use initia_move_compiler::unit_test_factory::InitiaUnitTestFactory;
1618

1719
use move_cli::base::test::{run_move_unit_tests_with_factory, UnitTestResult};
1820
use move_core_types::effects::ChangeSet;

crates/e2e-move-tests/src/tests/view_output.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,8 @@ fn test_view_output() {
4646
module: module_name,
4747
name: struct_name,
4848
type_args: vec![]
49-
})).to_string(),
49+
}))
50+
.to_string(),
5051
"{\"arg\":\"hello world\",\"type_arg\":\"u256\"}".to_string()
5152
)])
5253
.into_inner(),

crates/json/src/json_to_move.rs

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,20 @@ fn convert_json_value_to_move_value<S: StructResolver, R: ResourceResolver>(
137137
.ok_or_else(deserialization_error)?;
138138
let full_name = format!("{}::{}", st.module.short_str_lossless(), st.name);
139139
match full_name.as_str() {
140+
// JSONValue and JSONObject are not supported as entry function arguments
141+
//
142+
// "0x1::json::JSONValue" => MoveValue::vector_u8(
143+
// serde_json::to_vec(&json_val).map_err(deserialization_error_with_msg)?,
144+
// ),
145+
// "0x1::json::JSONObject" => {
146+
// let json_obj = json_val.as_object().ok_or_else(deserialization_error)?.to_owned();
147+
// let elems = json_obj.into_iter().map(|(k, v)| {
148+
// let key = k.into_bytes();
149+
// let value = serde_json::to_vec(&v).map_err(deserialization_error_with_msg)?;
150+
// Ok(MoveValue::Struct(MoveStruct::new(vec![MoveValue::vector_u8(key), MoveValue::vector_u8(value)])))
151+
// }).collect::<VMResult<Vec<_>>>()?;
152+
// MoveValue::Vector(elems)
153+
// },
140154
"0x1::string::String" => MoveValue::vector_u8(
141155
json_val.as_str().ok_or_else(deserialization_error)?.into(),
142156
),
@@ -780,10 +794,9 @@ mod json_arg_testing {
780794
#[test]
781795
fn test_deserialize_json_args_big_uint() {
782796
let mut mock_state = mock_state();
783-
mock_state.structs.insert(
784-
StructNameIndex(0),
785-
Arc::new(for_test("biguint", "BigUint")),
786-
);
797+
mock_state
798+
.structs
799+
.insert(StructNameIndex(0), Arc::new(for_test("biguint", "BigUint")));
787800

788801
let state_view = StateViewImpl::new(&mock_state);
789802

@@ -823,7 +836,12 @@ mod json_arg_testing {
823836

824837
assert_eq!(
825838
result,
826-
bcs::to_bytes(&BigUint::from_u128(1234567u128 * (1e14 as u128)).unwrap().to_bytes_le()).unwrap()
839+
bcs::to_bytes(
840+
&BigUint::from_u128(1234567u128 * (1e14 as u128))
841+
.unwrap()
842+
.to_bytes_le()
843+
)
844+
.unwrap()
827845
);
828846

829847
// invalid negative

crates/json/src/json_to_value.rs

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,28 @@ pub fn convert_json_value_to_value(
110110
let full_name =
111111
format!("{}::{}", type_.module_id().short_str_lossless(), type_.name);
112112
match full_name.as_str() {
113+
"0x1::json::JSONValue" => Value::struct_(Struct::pack(vec![Value::vector_u8(
114+
serde_json::to_vec(&json_val).map_err(deserialization_error_with_msg)?,
115+
)])),
116+
"0x1::json::JSONObject" => {
117+
let json_obj = json_val
118+
.as_object()
119+
.ok_or_else(deserialization_error)?
120+
.to_owned();
121+
let elems = json_obj
122+
.into_iter()
123+
.map(|(k, v)| {
124+
let key = k.into_bytes();
125+
let value = serde_json::to_vec(&v)
126+
.map_err(deserialization_error_with_msg)?;
127+
Ok(Value::struct_(Struct::pack(vec![
128+
Value::vector_u8(key),
129+
Value::vector_u8(value),
130+
])))
131+
})
132+
.collect::<VMResult<Vec<_>>>()?;
133+
Value::struct_(Struct::pack(vec![Value::vector_for_testing_only(elems)]))
134+
}
113135
"0x1::string::String" => Value::struct_(Struct::pack(vec![Value::vector_u8(
114136
json_val
115137
.as_str()
@@ -598,4 +620,80 @@ mod json_arg_testing {
598620
let arg = b"\"-123.4567\"";
599621
_ = deserialize_json_to_value(&layout, arg).unwrap_err();
600622
}
623+
624+
#[test]
625+
fn test_deserialize_json_to_value_json_value() {
626+
let layout = MoveTypeLayout::Struct(MoveStructLayout::with_types(
627+
StructTag {
628+
address: AccountAddress::ONE,
629+
module: ident_str!("json").into(),
630+
name: ident_str!("JSONValue").into(),
631+
type_args: vec![],
632+
},
633+
vec![MoveFieldLayout {
634+
name: ident_str!("value").into(),
635+
layout: MoveTypeLayout::Vector(Box::new(MoveTypeLayout::U8)),
636+
}],
637+
));
638+
639+
let arg = b"\"123\"";
640+
let result = deserialize_json_to_value(&layout, arg).unwrap();
641+
assert!(result
642+
.equals(&Value::struct_(Struct::pack(vec![Value::vector_u8(
643+
b"\"123\"".to_vec()
644+
)])))
645+
.unwrap());
646+
}
647+
648+
#[test]
649+
fn test_deserialize_json_to_value_json_object() {
650+
let layout = MoveTypeLayout::Struct(MoveStructLayout::with_types(
651+
StructTag {
652+
address: AccountAddress::ONE,
653+
module: ident_str!("json").into(),
654+
name: ident_str!("JSONObject").into(),
655+
type_args: vec![],
656+
},
657+
vec![MoveFieldLayout {
658+
name: ident_str!("elems").into(),
659+
layout: MoveTypeLayout::Vector(Box::new(MoveTypeLayout::Struct(
660+
MoveStructLayout::with_types(
661+
StructTag {
662+
address: AccountAddress::ONE,
663+
module: ident_str!("json").into(),
664+
name: ident_str!("Element").into(),
665+
type_args: vec![],
666+
},
667+
vec![
668+
MoveFieldLayout {
669+
name: ident_str!("key").into(),
670+
layout: MoveTypeLayout::Vector(Box::new(MoveTypeLayout::U8)),
671+
},
672+
MoveFieldLayout {
673+
name: ident_str!("value").into(),
674+
layout: MoveTypeLayout::Vector(Box::new(MoveTypeLayout::U8)),
675+
},
676+
],
677+
),
678+
))),
679+
}],
680+
));
681+
682+
let arg = b"{\"key1\": \"value1\", \"key2\": \"value2\"}";
683+
let result = deserialize_json_to_value(&layout, arg).unwrap();
684+
assert!(result
685+
.equals(&Value::struct_(Struct::pack(vec![
686+
Value::vector_for_testing_only(vec![
687+
Value::struct_(Struct::pack(vec![
688+
Value::vector_u8(b"key1".to_vec()),
689+
Value::vector_u8(b"\"value1\"".to_vec())
690+
])),
691+
Value::struct_(Struct::pack(vec![
692+
Value::vector_u8(b"key2".to_vec()),
693+
Value::vector_u8(b"\"value2\"".to_vec())
694+
]))
695+
])
696+
])))
697+
.unwrap());
698+
}
601699
}

crates/json/src/move_to_json.rs

Lines changed: 162 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,11 @@ fn convert_move_value_to_json_value(val: &MoveValue, depth: usize) -> VMResult<J
8181
// check the struct type is string
8282
// if yes, then convert move value to json string
8383
// else, execute convert function recursively
84-
if is_utf8_string(type_) {
84+
if is_json_value(type_) {
85+
convert_json_value_to_json_value(&fields[0].1)
86+
} else if is_json_object(type_) {
87+
convert_json_object_to_json_value(&fields[0].1)
88+
} else if is_utf8_string(type_) {
8589
convert_string_to_json_value(&fields[0].1)
8690
} else if is_biguint(type_) {
8791
convert_biguint_to_json_value(&fields[0].1)
@@ -124,6 +128,51 @@ fn convert_move_value_to_json_value(val: &MoveValue, depth: usize) -> VMResult<J
124128
}
125129
}
126130

131+
fn bytes_from_move_value(val: &MoveValue) -> VMResult<Vec<u8>> {
132+
match val {
133+
MoveValue::Vector(bytes_val) => bytes_val
134+
.iter()
135+
.map(|byte_val| match byte_val {
136+
MoveValue::U8(byte) => Ok(*byte),
137+
_ => Err(deserialization_error_with_msg("Expected U8 in vector")),
138+
})
139+
.collect::<VMResult<Vec<u8>>>(),
140+
_ => Err(deserialization_error_with_msg("Expected vector of U8s")),
141+
}
142+
}
143+
144+
fn convert_json_value_to_json_value(val: &MoveValue) -> VMResult<JSONValue> {
145+
let bz = bytes_from_move_value(val)?;
146+
serde_json::from_slice(&bz).map_err(deserialization_error_with_msg)
147+
}
148+
149+
fn convert_json_object_to_json_value(val: &MoveValue) -> VMResult<JSONValue> {
150+
let elems = match val {
151+
MoveValue::Vector(elems) => elems
152+
.iter()
153+
.map(|elem| match elem {
154+
MoveValue::Struct(
155+
MoveStruct::WithTypes { type_: _, fields }
156+
| MoveStruct::WithFields(fields)
157+
| MoveStruct::WithVariantFields(_, _, fields),
158+
) => {
159+
let key =
160+
std::str::from_utf8(&bytes_from_move_value(&fields.first().unwrap().1)?)
161+
.map_err(deserialization_error_with_msg)?
162+
.to_string();
163+
let val = convert_json_value_to_json_value(&fields.get(1).unwrap().1)?;
164+
165+
Ok((key, val))
166+
}
167+
_ => unreachable!(),
168+
})
169+
.collect::<VMResult<Map<_, _>>>()?,
170+
_ => unreachable!(),
171+
};
172+
173+
Ok(JSONValue::Object(elems))
174+
}
175+
127176
fn convert_string_to_json_value(val: &MoveValue) -> VMResult<JSONValue> {
128177
let bz: Vec<u8> = match val {
129178
MoveValue::Vector(bytes_val) => bytes_val
@@ -232,6 +281,18 @@ fn convert_object_to_json_value(val: &MoveValue) -> VMResult<JSONValue> {
232281
}
233282

234283
// check functions
284+
fn is_json_value(type_: &StructTag) -> bool {
285+
type_.address == CORE_CODE_ADDRESS
286+
&& type_.module.as_str() == "json"
287+
&& type_.name.as_str() == "JSONValue"
288+
}
289+
290+
fn is_json_object(type_: &StructTag) -> bool {
291+
type_.address == CORE_CODE_ADDRESS
292+
&& type_.module.as_str() == "json"
293+
&& type_.name.as_str() == "JSONObject"
294+
}
295+
235296
fn is_utf8_string(type_: &StructTag) -> bool {
236297
type_.address == CORE_CODE_ADDRESS
237298
&& type_.module.as_str() == "string"
@@ -453,5 +514,105 @@ mod move_to_json_tests {
453514
});
454515
let val = convert_move_value_to_json_value(&mv, 1).unwrap();
455516
assert_eq!(val, json!(addr.to_hex_literal()));
517+
518+
// json value
519+
let mv = MoveValue::Struct(MoveStruct::WithTypes {
520+
type_: StructTag {
521+
address: CORE_CODE_ADDRESS,
522+
module: ident_str!("json").into(),
523+
name: ident_str!("JSONValue").into(),
524+
type_args: vec![],
525+
},
526+
fields: vec![(
527+
ident_str!("val").into(),
528+
MoveValue::Vector(vec![
529+
MoveValue::U8(34),
530+
MoveValue::U8(109),
531+
MoveValue::U8(111),
532+
MoveValue::U8(118),
533+
MoveValue::U8(101),
534+
MoveValue::U8(34),
535+
]),
536+
)],
537+
});
538+
let val = convert_move_value_to_json_value(&mv, 1).unwrap();
539+
assert_eq!(val, json!("move"));
540+
541+
// json object
542+
let mv = MoveValue::Struct(MoveStruct::WithTypes {
543+
type_: StructTag {
544+
address: CORE_CODE_ADDRESS,
545+
module: ident_str!("json").into(),
546+
name: ident_str!("JSONObject").into(),
547+
type_args: vec![],
548+
},
549+
fields: vec![(
550+
ident_str!("elems").into(),
551+
MoveValue::Vector(vec![
552+
MoveValue::Struct(MoveStruct::WithTypes {
553+
type_: StructTag {
554+
address: CORE_CODE_ADDRESS,
555+
module: ident_str!("json").into(),
556+
name: ident_str!("Element").into(),
557+
type_args: vec![],
558+
},
559+
fields: vec![
560+
(
561+
ident_str!("key").into(),
562+
MoveValue::Vector(vec![
563+
MoveValue::U8(109),
564+
MoveValue::U8(111),
565+
MoveValue::U8(118),
566+
MoveValue::U8(101),
567+
]),
568+
),
569+
(
570+
ident_str!("value").into(),
571+
MoveValue::Vector(vec![
572+
MoveValue::U8(34),
573+
MoveValue::U8(109),
574+
MoveValue::U8(111),
575+
MoveValue::U8(118),
576+
MoveValue::U8(101),
577+
MoveValue::U8(34),
578+
]),
579+
),
580+
],
581+
}),
582+
MoveValue::Struct(MoveStruct::WithTypes {
583+
type_: StructTag {
584+
address: CORE_CODE_ADDRESS,
585+
module: ident_str!("json").into(),
586+
name: ident_str!("Element").into(),
587+
type_args: vec![],
588+
},
589+
fields: vec![
590+
(
591+
ident_str!("key").into(),
592+
MoveValue::Vector(vec![MoveValue::U8(102)]),
593+
),
594+
(
595+
ident_str!("value").into(),
596+
MoveValue::Vector(vec![
597+
MoveValue::U8(110),
598+
MoveValue::U8(117),
599+
MoveValue::U8(108),
600+
MoveValue::U8(108),
601+
]),
602+
),
603+
],
604+
}),
605+
]),
606+
)],
607+
});
608+
609+
let val = convert_move_value_to_json_value(&mv, 1).unwrap();
610+
assert_eq!(
611+
val,
612+
json!({
613+
"move": json!("move"),
614+
"f": json!(null),
615+
})
616+
);
456617
}
457618
}

0 commit comments

Comments
 (0)