diff --git a/Cargo.lock b/Cargo.lock index 8194711a64..8bc8cfc50a 100755 --- a/Cargo.lock +++ b/Cargo.lock @@ -248,6 +248,8 @@ dependencies = [ "multiversx-sc", "multiversx-sc-modules", "multiversx-sc-scenario", + "serde", + "serde_json", ] [[package]] @@ -655,6 +657,15 @@ dependencies = [ "cc", ] +[[package]] +name = "cobs" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fa961b519f0b462e3a3b4a34b64d119eeaca1d59af726fe450bbba07a9fc0a1" +dependencies = [ + "thiserror 2.0.12", +] + [[package]] name = "colorchoice" version = "1.0.4" @@ -3109,6 +3120,8 @@ dependencies = [ "multiversx-sc-codec", "multiversx-sc-derive", "num-traits", + "postcard", + "serde", "unwrap-infallible", ] @@ -3833,6 +3846,16 @@ dependencies = [ "portable-atomic", ] +[[package]] +name = "postcard" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c1de96e20f51df24ca73cafcc4690e044854d803259db27a00a461cb3b9d17a" +dependencies = [ + "cobs", + "serde", +] + [[package]] name = "ppv-lite86" version = "0.2.21" diff --git a/contracts/feature-tests/basic-features/Cargo.toml b/contracts/feature-tests/basic-features/Cargo.toml index 6b8ceb43d9..a504165e41 100644 --- a/contracts/feature-tests/basic-features/Cargo.toml +++ b/contracts/feature-tests/basic-features/Cargo.toml @@ -15,6 +15,15 @@ barnard = ["multiversx-sc/barnard"] version = "0.60.0" path = "../../../framework/base" +[dependencies.serde] +version = "1.0" +default-features = false +features = ["derive"] + +[dependencies.serde_json] +version = "1.0" +default-features = false + [dev-dependencies.multiversx-sc-scenario] version = "0.60.0" features = ["wasmer-experimental"] diff --git a/contracts/feature-tests/basic-features/src/basic_features_main.rs b/contracts/feature-tests/basic-features/src/basic_features_main.rs index c06756f744..dac52be228 100644 --- a/contracts/feature-tests/basic-features/src/basic_features_main.rs +++ b/contracts/feature-tests/basic-features/src/basic_features_main.rs @@ -21,6 +21,7 @@ pub mod managed_decimal_features; pub mod managed_map_features; pub mod managed_vec_features; pub mod non_zero_features; +pub mod serde_features; pub mod small_num_overflow_test_ops; pub mod special_roles_from_system_account; pub mod storage_direct_load; @@ -62,6 +63,7 @@ pub trait BasicFeatures: + managed_address_features::ManagedAddressFeatures + managed_buffer_features::ManagedBufferFeatures + managed_vec_features::ManagedVecFeatures + + serde_features::SerdeFeatures + storage_raw_api_features::StorageRawApiFeatures + storage_direct_load::StorageLoadFeatures + storage_direct_store::StorageStoreFeatures diff --git a/contracts/feature-tests/basic-features/src/serde_features.rs b/contracts/feature-tests/basic-features/src/serde_features.rs new file mode 100644 index 0000000000..4aefa85dd4 --- /dev/null +++ b/contracts/feature-tests/basic-features/src/serde_features.rs @@ -0,0 +1,36 @@ +use serde::{Deserialize, Serialize}; + +multiversx_sc::imports!(); + +multiversx_sc::derive_imports!(); + +#[type_abi] +#[derive( + NestedEncode, + NestedDecode, + TopEncode, + TopDecode, + PartialEq, + Eq, + Debug, + Clone, + Serialize, + Deserialize, +)] +pub struct StructManaged { + pub m_buffer: ManagedBuffer, + pub m_vec_of_m_buffers: ManagedVec>, +} + +#[multiversx_sc::module] +pub trait SerdeFeatures { + #[endpoint] + fn managed_serialize(&self, json: ManagedBuffer) -> StructManaged { + todo!(); + } + + #[endpoint] + fn managed_deserialize(&self, m_struct: StructManaged) -> ManagedBuffer { + todo!(); + } +} diff --git a/framework/base/Cargo.toml b/framework/base/Cargo.toml index 35c702f37b..370e4d21a5 100644 --- a/framework/base/Cargo.toml +++ b/framework/base/Cargo.toml @@ -4,7 +4,10 @@ version = "0.60.0" edition = "2021" rust-version = "1.83" -authors = ["Andrei Marinica ", "MultiversX "] +authors = [ + "Andrei Marinica ", + "MultiversX ", +] license = "GPL-3.0-only" readme = "README.md" repository = "https://github.com/multiversx/mx-sdk-rs" @@ -12,7 +15,12 @@ homepage = "https://multiversx.com/" documentation = "https://docs.multiversx.com/" description = "MultiversX smart contract API" keywords = ["multiversx", "wasm", "webassembly", "blockchain", "contract"] -categories = ["no-std", "wasm", "cryptography::cryptocurrencies", "development-tools"] +categories = [ + "no-std", + "wasm", + "cryptography::cryptocurrencies", + "development-tools", +] [package.metadata.docs.rs] all-features = true @@ -26,6 +34,11 @@ esdt-token-payment-legacy-decode = [] barnard = [] [dependencies] +serde = { version = "1.0", default-features = false, features = [ + "derive", + "alloc", +] } +postcard = { version = "1.0", default-features = false } hex-literal = "1.0" bitflags = "2.9" num-traits = { version = "=0.2.19", default-features = false } diff --git a/framework/base/src/types/managed.rs b/framework/base/src/types/managed.rs index 3107f1ee3e..7687446527 100644 --- a/framework/base/src/types/managed.rs +++ b/framework/base/src/types/managed.rs @@ -1,11 +1,13 @@ mod basic; mod codec_util; +mod managed_serde; mod managed_type_trait; mod multi_value; mod wrapped; pub use basic::*; pub use codec_util::*; +pub use managed_serde::*; pub use managed_type_trait::ManagedType; pub use multi_value::*; pub use wrapped::*; diff --git a/framework/base/src/types/managed/managed_serde/from_managed_buffer.rs b/framework/base/src/types/managed/managed_serde/from_managed_buffer.rs new file mode 100644 index 0000000000..bb9c4f26f6 --- /dev/null +++ b/framework/base/src/types/managed/managed_serde/from_managed_buffer.rs @@ -0,0 +1,10 @@ +use postcard::from_bytes; +use serde::de::DeserializeOwned; + +use crate::{api::ManagedTypeApi, types::ManagedBuffer}; + +pub fn from_managed_buffer( + mb: &ManagedBuffer, +) -> Result { + mb.with_buffer_contents(|slice| from_bytes(slice)) +} diff --git a/framework/base/src/types/managed/managed_serde/from_managed_vec.rs b/framework/base/src/types/managed/managed_serde/from_managed_vec.rs new file mode 100644 index 0000000000..e00c60bc6d --- /dev/null +++ b/framework/base/src/types/managed/managed_serde/from_managed_vec.rs @@ -0,0 +1,9 @@ +use crate::{api::ManagedTypeApi, types::ManagedVec}; +use postcard::from_bytes; +use serde::de::DeserializeOwned; + +pub fn from_managed_vec( + mv: &ManagedVec, +) -> Result { + mv.with_self_as_slice(|mv_slice| from_bytes(mv_slice)) +} diff --git a/framework/base/src/types/managed/managed_serde/mod.rs b/framework/base/src/types/managed/managed_serde/mod.rs new file mode 100644 index 0000000000..53d1df28f0 --- /dev/null +++ b/framework/base/src/types/managed/managed_serde/mod.rs @@ -0,0 +1,4 @@ +pub mod from_managed_buffer; +pub mod from_managed_vec; +pub mod to_managed_buffer; +pub mod to_managed_vec; diff --git a/framework/base/src/types/managed/managed_serde/to_managed_buffer.rs b/framework/base/src/types/managed/managed_serde/to_managed_buffer.rs new file mode 100644 index 0000000000..637051b1bb --- /dev/null +++ b/framework/base/src/types/managed/managed_serde/to_managed_buffer.rs @@ -0,0 +1,15 @@ +use serde::Serialize; + +use crate::{ + api::ManagedTypeApi, + types::{to_managed_vec::to_managed_vec, ManagedBuffer}, +}; + +struct ManagedBufferWriter<'a, M: ManagedTypeApi> { + buffer: &'a mut ManagedBuffer, +} + +pub fn to_managed_buffer(obj: &T) -> ManagedBuffer { + let mv = to_managed_vec(obj); + mv.buffer +} diff --git a/framework/base/src/types/managed/managed_serde/to_managed_vec.rs b/framework/base/src/types/managed/managed_serde/to_managed_vec.rs new file mode 100644 index 0000000000..6e32e29144 --- /dev/null +++ b/framework/base/src/types/managed/managed_serde/to_managed_vec.rs @@ -0,0 +1,22 @@ +use crate::types::ManagedVec; +use postcard::to_slice; +use serde::Serialize; + +use crate::api::ManagedTypeApi; + +pub fn to_managed_vec(obj: &T) -> ManagedVec { + let mut buffer: ManagedVec = ManagedVec::new(); + + const MAX: usize = 1024; + let mut temp = [0u8; MAX]; + + let len = to_slice(obj, &mut temp) + .expect("serialization failed") + .len(); + + for byte in &temp[..len] { + buffer.push(*byte); + } + + buffer +}