diff --git a/Cargo.lock b/Cargo.lock index 792b246d..d44daf69 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,15 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + [[package]] name = "arbitrary" version = "1.1.3" @@ -23,6 +32,132 @@ version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" +[[package]] +name = "bumpalo" +version = "3.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1ad822118d20d2c234f427000d5acc36eabe1e29a348c89b63dd60b13f28e5d" + +[[package]] +name = "cc" +version = "1.0.73" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "chrono" +version = "0.4.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfd4d1b31faaa3a89d7934dbded3111da0d2ef28e3ebccdb4f0179f5929d1ef1" +dependencies = [ + "iana-time-zone", + "num-integer", + "num-traits", + "serde", + "winapi", +] + +[[package]] +name = "codespan-reporting" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e" +dependencies = [ + "termcolor", + "unicode-width", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" + +[[package]] +name = "cxx" +version = "1.0.78" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19f39818dcfc97d45b03953c1292efc4e80954e1583c4aa770bac1383e2310a4" +dependencies = [ + "cc", + "cxxbridge-flags", + "cxxbridge-macro", + "link-cplusplus", +] + +[[package]] +name = "cxx-build" +version = "1.0.78" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e580d70777c116df50c390d1211993f62d40302881e54d4b79727acb83d0199" +dependencies = [ + "cc", + "codespan-reporting", + "once_cell", + "proc-macro2", + "quote", + "scratch", + "syn", +] + +[[package]] +name = "cxxbridge-flags" +version = "1.0.78" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56a46460b88d1cec95112c8c363f0e2c39afdb237f60583b0b36343bf627ea9c" + +[[package]] +name = "cxxbridge-macro" +version = "1.0.78" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "747b608fecf06b0d72d440f27acc99288207324b793be2c17991839f3d4995ea" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "darling" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4529658bdda7fd6769b8614be250cdcfc3aeb0ee72fe66f9e41e5e5eb73eac02" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "649c91bc01e8b1eac09fb91e8dbc7d517684ca6be8ebc75bb9cafc894f9fdb6f" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn", +] + +[[package]] +name = "darling_macro" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddfc69c5bfcbd2fc09a0f38451d2daf0e372e367986a83906d1b0dbc88134fb5" +dependencies = [ + "darling_core", + "quote", + "syn", +] + [[package]] name = "derive_arbitrary" version = "1.1.3" @@ -34,6 +169,107 @@ dependencies = [ "syn", ] +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +dependencies = [ + "serde", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.51" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5a6ef98976b22b3b7f2f3a806f858cb862044cfa66805aa3ad84cb3d3b785ed" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "winapi", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fde6edd6cef363e9359ed3c98ba64590ba9eecba2293eb5a723ab32aee8926aa" +dependencies = [ + "cxx", + "cxx-build", +] + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "indexmap" +version = "1.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e" +dependencies = [ + "autocfg", + "hashbrown", + "serde", +] + +[[package]] +name = "itoa" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4217ad341ebadf8d8e724e264f13e593e0648f5b3e94b3896a5df283be015ecc" + +[[package]] +name = "js-sys" +version = "0.3.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49409df3e3bf0856b916e2ceaca09ee28e6871cf7d9ce97a692cacfdb2a25a47" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "libc" +version = "0.2.135" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68783febc7782c6c5cb401fbda4de5a9898be1762314da0bb2c10ced61f18b0c" + +[[package]] +name = "link-cplusplus" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9272ab7b96c9046fbc5bc56c06c117cb639fe2d509df0c421cad82d2915cf369" +dependencies = [ + "cc", +] + +[[package]] +name = "log" +version = "0.4.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" +dependencies = [ + "cfg-if", +] + [[package]] name = "num-bigint" version = "0.4.3" @@ -64,6 +300,21 @@ dependencies = [ "autocfg", ] +[[package]] +name = "num_threads" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2819ce041d2ee131036f4fc9d6ae7ae125a3a40e97ba64d04fe799ad9dabbb44" +dependencies = [ + "libc", +] + +[[package]] +name = "once_cell" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e82dad04139b71a90c080c8463fe0dc7902db5192d939bd0950f074d014339e1" + [[package]] name = "proc-macro2" version = "1.0.40" @@ -82,6 +333,18 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "ryu" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09" + +[[package]] +name = "scratch" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8132065adcfd6e02db789d9285a0deb2f3fcb04002865ab67d5fb103533898" + [[package]] name = "serde" version = "1.0.139" @@ -102,16 +365,64 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41feea4228a6f1cd09ec7a3593a682276702cd67b5273544757dae23c096f074" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_with" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "368f2d60d049ea019a84dcd6687b0d1e0030fe663ae105039bdf967ed5e6a9a7" +dependencies = [ + "base64", + "chrono", + "hex", + "indexmap", + "serde", + "serde_json", + "serde_with_macros", + "time", +] + +[[package]] +name = "serde_with_macros" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ccadfacf6cf10faad22bbadf55986bdd0856edfb5d9210aa1dcf1f516e84e93" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "stellar-xdr" version = "0.0.6" dependencies = [ "arbitrary", "base64", + "hex", "num-bigint", "serde", + "serde_json", + "serde_with", ] +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + [[package]] name = "syn" version = "1.0.98" @@ -123,8 +434,120 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "termcolor" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "time" +version = "0.3.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d634a985c4d4238ec39cacaed2e7ae552fbd3c476b552c1deac3021b7d7eaf0c" +dependencies = [ + "itoa", + "libc", + "num_threads", + "serde", +] + [[package]] name = "unicode-ident" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5bd2fe26506023ed7b5e1e315add59d6f584c621d037f9368fea9cfb988f368c" + +[[package]] +name = "unicode-width" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" + +[[package]] +name = "wasm-bindgen" +version = "0.2.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eaf9f5aceeec8be17c128b2e93e031fb8a4d469bb9c4ae2d7dc1888b26887268" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c8ffb332579b0557b52d268b91feab8df3615f265d5270fec2a8c95b17c1142" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "052be0f94026e6cbc75cdefc9bae13fd6052cdcaf532fa6c45e7ae33a1e6c810" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/Cargo.toml b/Cargo.toml index 9989f1c8..5efb76fb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,20 +12,26 @@ rust-version = "1.64" [dependencies] base64 = { version = "0.13.0", optional = true } serde = { version = "1.0.139", features = ["derive"], optional = true } +serde_with = { version = "2.0.1", optional = true } +hex = { version = "0.4.3", optional = true } num-bigint = { version = "0.4.3", optional = true } arbitrary = {version = "1.1.3", features = ["derive"], optional = true} +[dev_dependencies] +serde_json = "1.0.86" + [features] default = ["std"] std = ["alloc"] -alloc = [] +alloc = ["dep:hex"] next = [] # Features dependent on optional dependencies. base64 = ["std", "dep:base64"] -serde = ["alloc", "dep:serde"] +serde = ["alloc", "dep:serde", "dep:serde_with", "hex/serde"] num-bigint = ["alloc", "dep:num-bigint"] arbitrary = ["std", "dep:arbitrary"] +hex = [] [package.metadata.docs.rs] all-features = true diff --git a/Makefile b/Makefile index 04c84086..b78ddab8 100644 --- a/Makefile +++ b/Makefile @@ -25,7 +25,7 @@ XDR_FILES_LOCAL_NEXT=$(addprefix xdr/next/,$(XDR_FILES_NEXT)) export RUSTFLAGS=-Dwarnings -Dclippy::all -Dclippy::pedantic -CARGO_HACK_ARGS=--feature-powerset --exclude-features default --group-features base64,serde,num-bigint,arbitrary +CARGO_HACK_ARGS=--feature-powerset --exclude-features default --group-features base64,serde,num-bigint,arbitrary,hex all: build test diff --git a/src/curr.rs b/src/curr.rs index e801977a..b7a9ac5e 100644 --- a/src/curr.rs +++ b/src/curr.rs @@ -89,6 +89,8 @@ pub enum Error { LengthMismatch, NonZeroPadding, Utf8Error(core::str::Utf8Error), + #[cfg(feature = "alloc")] + InvalidHex, #[cfg(feature = "std")] Io(io::Error), } @@ -129,6 +131,8 @@ impl fmt::Display for Error { Error::LengthMismatch => write!(f, "xdr value length does not match"), Error::NonZeroPadding => write!(f, "xdr padding contains non-zero bytes"), Error::Utf8Error(e) => write!(f, "{}", e), + #[cfg(feature = "alloc")] + Error::InvalidHex => write!(f, "hex invalid"), #[cfg(feature = "std")] Error::Io(e) => write!(f, "{}", e), } @@ -657,6 +661,8 @@ impl WriteXdr for [T; N] { } } +// VecM ------------------------------------------------------------------------ + #[cfg(feature = "alloc")] #[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] @@ -670,21 +676,825 @@ pub struct VecM(Vec) where T: 'static; -impl Deref for VecM { - type Target = Vec; +impl Deref for VecM { + type Target = Vec; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl Default for VecM { + fn default() -> Self { + Self(Vec::default()) + } +} + +impl VecM { + pub const MAX_LEN: usize = { MAX as usize }; + + #[must_use] + #[allow(clippy::unused_self)] + pub fn max_len(&self) -> usize { + Self::MAX_LEN + } + + #[must_use] + pub fn as_vec(&self) -> &Vec { + self.as_ref() + } +} + +impl VecM { + #[must_use] + #[cfg(feature = "alloc")] + pub fn to_vec(&self) -> Vec { + self.into() + } + + #[must_use] + pub fn into_vec(self) -> Vec { + self.into() + } +} + +impl VecM { + #[cfg(feature = "alloc")] + pub fn to_string(&self) -> Result { + self.try_into() + } + + #[cfg(feature = "alloc")] + pub fn into_string(self) -> Result { + self.try_into() + } + + #[cfg(feature = "alloc")] + #[must_use] + pub fn to_string_lossy(&self) -> String { + String::from_utf8_lossy(&self.0).into_owned() + } + + #[cfg(feature = "alloc")] + #[must_use] + pub fn into_string_lossy(self) -> String { + String::from_utf8_lossy(&self.0).into_owned() + } +} + +impl VecM { + #[must_use] + pub fn to_option(&self) -> Option { + if self.len() > 0 { + Some(self.0[0].clone()) + } else { + None + } + } +} + +#[cfg(not(feature = "alloc"))] +impl From> for Option { + #[must_use] + fn from(v: VecM) -> Self { + v.to_option() + } +} + +#[cfg(feature = "alloc")] +impl VecM { + #[must_use] + pub fn into_option(mut self) -> Option { + self.0.drain(..).next() + } +} + +#[cfg(feature = "alloc")] +impl From> for Option { + #[must_use] + fn from(v: VecM) -> Self { + v.into_option() + } +} + +impl TryFrom> for VecM { + type Error = Error; + + fn try_from(v: Vec) -> Result { + let len: u32 = v.len().try_into().map_err(|_| Error::LengthExceedsMax)?; + if len <= MAX { + Ok(VecM(v)) + } else { + Err(Error::LengthExceedsMax) + } + } +} + +impl From> for Vec { + #[must_use] + fn from(v: VecM) -> Self { + v.0 + } +} + +#[cfg(feature = "alloc")] +impl From<&VecM> for Vec { + #[must_use] + fn from(v: &VecM) -> Self { + v.0.clone() + } +} + +impl AsRef> for VecM { + #[must_use] + fn as_ref(&self) -> &Vec { + &self.0 + } +} + +#[cfg(feature = "alloc")] +impl TryFrom<&Vec> for VecM { + type Error = Error; + + fn try_from(v: &Vec) -> Result { + v.as_slice().try_into() + } +} + +#[cfg(feature = "alloc")] +impl TryFrom<&[T]> for VecM { + type Error = Error; + + fn try_from(v: &[T]) -> Result { + let len: u32 = v.len().try_into().map_err(|_| Error::LengthExceedsMax)?; + if len <= MAX { + Ok(VecM(v.to_vec())) + } else { + Err(Error::LengthExceedsMax) + } + } +} + +impl AsRef<[T]> for VecM { + #[cfg(feature = "alloc")] + #[must_use] + fn as_ref(&self) -> &[T] { + self.0.as_ref() + } + #[cfg(not(feature = "alloc"))] + #[must_use] + fn as_ref(&self) -> &[T] { + self.0 + } +} + +#[cfg(feature = "alloc")] +impl TryFrom<[T; N]> for VecM { + type Error = Error; + + fn try_from(v: [T; N]) -> Result { + let len: u32 = v.len().try_into().map_err(|_| Error::LengthExceedsMax)?; + if len <= MAX { + Ok(VecM(v.to_vec())) + } else { + Err(Error::LengthExceedsMax) + } + } +} + +#[cfg(feature = "alloc")] +impl TryFrom> for [T; N] { + type Error = VecM; + + fn try_from(v: VecM) -> core::result::Result { + let s: [T; N] = v.0.try_into().map_err(|v: Vec| VecM::(v))?; + Ok(s) + } +} + +#[cfg(feature = "alloc")] +impl TryFrom<&[T; N]> for VecM { + type Error = Error; + + fn try_from(v: &[T; N]) -> Result { + let len: u32 = v.len().try_into().map_err(|_| Error::LengthExceedsMax)?; + if len <= MAX { + Ok(VecM(v.to_vec())) + } else { + Err(Error::LengthExceedsMax) + } + } +} + +#[cfg(not(feature = "alloc"))] +impl TryFrom<&'static [T; N]> for VecM { + type Error = Error; + + fn try_from(v: &'static [T; N]) -> Result { + let len: u32 = v.len().try_into().map_err(|_| Error::LengthExceedsMax)?; + if len <= MAX { + Ok(VecM(v)) + } else { + Err(Error::LengthExceedsMax) + } + } +} + +#[cfg(feature = "alloc")] +impl TryFrom<&String> for VecM { + type Error = Error; + + fn try_from(v: &String) -> Result { + let len: u32 = v.len().try_into().map_err(|_| Error::LengthExceedsMax)?; + if len <= MAX { + Ok(VecM(v.as_bytes().to_vec())) + } else { + Err(Error::LengthExceedsMax) + } + } +} + +#[cfg(feature = "alloc")] +impl TryFrom for VecM { + type Error = Error; + + fn try_from(v: String) -> Result { + let len: u32 = v.len().try_into().map_err(|_| Error::LengthExceedsMax)?; + if len <= MAX { + Ok(VecM(v.into())) + } else { + Err(Error::LengthExceedsMax) + } + } +} + +#[cfg(feature = "alloc")] +impl TryFrom> for String { + type Error = Error; + + fn try_from(v: VecM) -> Result { + Ok(String::from_utf8(v.0)?) + } +} + +#[cfg(feature = "alloc")] +impl TryFrom<&VecM> for String { + type Error = Error; + + fn try_from(v: &VecM) -> Result { + Ok(core::str::from_utf8(v.as_ref())?.to_owned()) + } +} + +#[cfg(feature = "alloc")] +impl TryFrom<&str> for VecM { + type Error = Error; + + fn try_from(v: &str) -> Result { + let len: u32 = v.len().try_into().map_err(|_| Error::LengthExceedsMax)?; + if len <= MAX { + Ok(VecM(v.into())) + } else { + Err(Error::LengthExceedsMax) + } + } +} + +#[cfg(not(feature = "alloc"))] +impl TryFrom<&'static str> for VecM { + type Error = Error; + + fn try_from(v: &'static str) -> Result { + let len: u32 = v.len().try_into().map_err(|_| Error::LengthExceedsMax)?; + if len <= MAX { + Ok(VecM(v.as_bytes())) + } else { + Err(Error::LengthExceedsMax) + } + } +} + +impl<'a, const MAX: u32> TryFrom<&'a VecM> for &'a str { + type Error = Error; + + fn try_from(v: &'a VecM) -> Result { + Ok(core::str::from_utf8(v.as_ref())?) + } +} + +impl ReadXdr for VecM { + #[cfg(feature = "std")] + fn read_xdr(r: &mut impl Read) -> Result { + let len: u32 = u32::read_xdr(r)?; + if len > MAX { + return Err(Error::LengthExceedsMax); + } + + let mut vec = vec![0u8; len as usize]; + r.read_exact(&mut vec)?; + + let pad = &mut [0u8; 3][..pad_len(len as usize)]; + r.read_exact(pad)?; + if pad.iter().any(|b| *b != 0) { + return Err(Error::NonZeroPadding); + } + + Ok(VecM(vec)) + } +} + +impl WriteXdr for VecM { + #[cfg(feature = "std")] + fn write_xdr(&self, w: &mut impl Write) -> Result<()> { + let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; + len.write_xdr(w)?; + + w.write_all(&self.0)?; + + w.write_all(&[0u8; 3][..pad_len(len as usize)])?; + + Ok(()) + } +} + +impl ReadXdr for VecM { + #[cfg(feature = "std")] + fn read_xdr(r: &mut impl Read) -> Result { + let len = u32::read_xdr(r)?; + if len > MAX { + return Err(Error::LengthExceedsMax); + } + + let mut vec = Vec::with_capacity(len as usize); + for _ in 0..len { + let t = T::read_xdr(r)?; + vec.push(t); + } + + Ok(VecM(vec)) + } +} + +impl WriteXdr for VecM { + #[cfg(feature = "std")] + fn write_xdr(&self, w: &mut impl Write) -> Result<()> { + let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; + len.write_xdr(w)?; + + for t in &self.0 { + t.write_xdr(w)?; + } + + Ok(()) + } +} + +// BytesM ------------------------------------------------------------------------ + +#[cfg(feature = "alloc")] +#[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[cfg_attr( + feature = "serde", + derive(serde_with::SerializeDisplay, serde_with::DeserializeFromStr) +)] +#[cfg_attr(feature = "arbitrary", derive(Arbitrary))] +pub struct BytesM(Vec); + +#[cfg(not(feature = "alloc"))] +#[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[cfg_attr(feature = "arbitrary", derive(Arbitrary))] +pub struct BytesM(Vec); + +impl core::fmt::Display for BytesM { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + #[cfg(feature = "alloc")] + let v = &self.0; + #[cfg(not(feature = "alloc"))] + let v = self.0; + for b in v { + write!(f, "{b:02x}")?; + } + Ok(()) + } +} + +impl core::fmt::Debug for BytesM { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + #[cfg(feature = "alloc")] + let v = &self.0; + #[cfg(not(feature = "alloc"))] + let v = self.0; + write!(f, "BytesM(")?; + for b in v { + write!(f, "{b:02x}")?; + } + write!(f, ")")?; + Ok(()) + } +} + +#[cfg(feature = "alloc")] +impl core::str::FromStr for BytesM { + type Err = Error; + fn from_str(s: &str) -> core::result::Result { + hex::decode(s).map_err(|_| Error::InvalidHex)?.try_into() + } +} + +impl Deref for BytesM { + type Target = Vec; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl Default for BytesM { + fn default() -> Self { + Self(Vec::default()) + } +} + +impl BytesM { + pub const MAX_LEN: usize = { MAX as usize }; + + #[must_use] + #[allow(clippy::unused_self)] + pub fn max_len(&self) -> usize { + Self::MAX_LEN + } + + #[must_use] + pub fn as_vec(&self) -> &Vec { + self.as_ref() + } +} + +impl BytesM { + #[must_use] + #[cfg(feature = "alloc")] + pub fn to_vec(&self) -> Vec { + self.into() + } + + #[must_use] + pub fn into_vec(self) -> Vec { + self.into() + } +} + +impl BytesM { + #[cfg(feature = "alloc")] + pub fn to_string(&self) -> Result { + self.try_into() + } + + #[cfg(feature = "alloc")] + pub fn into_string(self) -> Result { + self.try_into() + } + + #[cfg(feature = "alloc")] + #[must_use] + pub fn to_string_lossy(&self) -> String { + String::from_utf8_lossy(&self.0).into_owned() + } + + #[cfg(feature = "alloc")] + #[must_use] + pub fn into_string_lossy(self) -> String { + String::from_utf8_lossy(&self.0).into_owned() + } +} + +impl TryFrom> for BytesM { + type Error = Error; + + fn try_from(v: Vec) -> Result { + let len: u32 = v.len().try_into().map_err(|_| Error::LengthExceedsMax)?; + if len <= MAX { + Ok(BytesM(v)) + } else { + Err(Error::LengthExceedsMax) + } + } +} + +impl From> for Vec { + #[must_use] + fn from(v: BytesM) -> Self { + v.0 + } +} + +#[cfg(feature = "alloc")] +impl From<&BytesM> for Vec { + #[must_use] + fn from(v: &BytesM) -> Self { + v.0.clone() + } +} + +impl AsRef> for BytesM { + #[must_use] + fn as_ref(&self) -> &Vec { + &self.0 + } +} + +#[cfg(feature = "alloc")] +impl TryFrom<&Vec> for BytesM { + type Error = Error; + + fn try_from(v: &Vec) -> Result { + v.as_slice().try_into() + } +} + +#[cfg(feature = "alloc")] +impl TryFrom<&[u8]> for BytesM { + type Error = Error; + + fn try_from(v: &[u8]) -> Result { + let len: u32 = v.len().try_into().map_err(|_| Error::LengthExceedsMax)?; + if len <= MAX { + Ok(BytesM(v.to_vec())) + } else { + Err(Error::LengthExceedsMax) + } + } +} + +impl AsRef<[u8]> for BytesM { + #[cfg(feature = "alloc")] + #[must_use] + fn as_ref(&self) -> &[u8] { + self.0.as_ref() + } + #[cfg(not(feature = "alloc"))] + #[must_use] + fn as_ref(&self) -> &[u8] { + self.0 + } +} + +#[cfg(feature = "alloc")] +impl TryFrom<[u8; N]> for BytesM { + type Error = Error; + + fn try_from(v: [u8; N]) -> Result { + let len: u32 = v.len().try_into().map_err(|_| Error::LengthExceedsMax)?; + if len <= MAX { + Ok(BytesM(v.to_vec())) + } else { + Err(Error::LengthExceedsMax) + } + } +} + +#[cfg(feature = "alloc")] +impl TryFrom> for [u8; N] { + type Error = BytesM; + + fn try_from(v: BytesM) -> core::result::Result { + let s: [u8; N] = v.0.try_into().map_err(BytesM::)?; + Ok(s) + } +} + +#[cfg(feature = "alloc")] +impl TryFrom<&[u8; N]> for BytesM { + type Error = Error; + + fn try_from(v: &[u8; N]) -> Result { + let len: u32 = v.len().try_into().map_err(|_| Error::LengthExceedsMax)?; + if len <= MAX { + Ok(BytesM(v.to_vec())) + } else { + Err(Error::LengthExceedsMax) + } + } +} + +#[cfg(not(feature = "alloc"))] +impl TryFrom<&'static [u8; N]> for BytesM { + type Error = Error; + + fn try_from(v: &'static [u8; N]) -> Result { + let len: u32 = v.len().try_into().map_err(|_| Error::LengthExceedsMax)?; + if len <= MAX { + Ok(BytesM(v)) + } else { + Err(Error::LengthExceedsMax) + } + } +} + +#[cfg(feature = "alloc")] +impl TryFrom<&String> for BytesM { + type Error = Error; + + fn try_from(v: &String) -> Result { + let len: u32 = v.len().try_into().map_err(|_| Error::LengthExceedsMax)?; + if len <= MAX { + Ok(BytesM(v.as_bytes().to_vec())) + } else { + Err(Error::LengthExceedsMax) + } + } +} + +#[cfg(feature = "alloc")] +impl TryFrom for BytesM { + type Error = Error; + + fn try_from(v: String) -> Result { + let len: u32 = v.len().try_into().map_err(|_| Error::LengthExceedsMax)?; + if len <= MAX { + Ok(BytesM(v.into())) + } else { + Err(Error::LengthExceedsMax) + } + } +} + +#[cfg(feature = "alloc")] +impl TryFrom> for String { + type Error = Error; + + fn try_from(v: BytesM) -> Result { + Ok(String::from_utf8(v.0)?) + } +} + +#[cfg(feature = "alloc")] +impl TryFrom<&BytesM> for String { + type Error = Error; + + fn try_from(v: &BytesM) -> Result { + Ok(core::str::from_utf8(v.as_ref())?.to_owned()) + } +} + +#[cfg(feature = "alloc")] +impl TryFrom<&str> for BytesM { + type Error = Error; + + fn try_from(v: &str) -> Result { + let len: u32 = v.len().try_into().map_err(|_| Error::LengthExceedsMax)?; + if len <= MAX { + Ok(BytesM(v.into())) + } else { + Err(Error::LengthExceedsMax) + } + } +} + +#[cfg(not(feature = "alloc"))] +impl TryFrom<&'static str> for BytesM { + type Error = Error; + + fn try_from(v: &'static str) -> Result { + let len: u32 = v.len().try_into().map_err(|_| Error::LengthExceedsMax)?; + if len <= MAX { + Ok(BytesM(v.as_bytes())) + } else { + Err(Error::LengthExceedsMax) + } + } +} + +impl<'a, const MAX: u32> TryFrom<&'a BytesM> for &'a str { + type Error = Error; + + fn try_from(v: &'a BytesM) -> Result { + Ok(core::str::from_utf8(v.as_ref())?) + } +} + +impl ReadXdr for BytesM { + #[cfg(feature = "std")] + fn read_xdr(r: &mut impl Read) -> Result { + let len: u32 = u32::read_xdr(r)?; + if len > MAX { + return Err(Error::LengthExceedsMax); + } + + let mut vec = vec![0u8; len as usize]; + r.read_exact(&mut vec)?; + + let pad = &mut [0u8; 3][..pad_len(len as usize)]; + r.read_exact(pad)?; + if pad.iter().any(|b| *b != 0) { + return Err(Error::NonZeroPadding); + } + + Ok(BytesM(vec)) + } +} + +impl WriteXdr for BytesM { + #[cfg(feature = "std")] + fn write_xdr(&self, w: &mut impl Write) -> Result<()> { + let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; + len.write_xdr(w)?; + + w.write_all(&self.0)?; + + w.write_all(&[0u8; 3][..pad_len(len as usize)])?; + + Ok(()) + } +} + +// StringM ------------------------------------------------------------------------ + +#[cfg(feature = "alloc")] +#[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[cfg_attr( + feature = "serde", + derive(serde_with::SerializeDisplay, serde_with::DeserializeFromStr) +)] +#[cfg_attr(feature = "arbitrary", derive(Arbitrary))] +pub struct StringM(Vec); + +#[cfg(not(feature = "alloc"))] +#[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[cfg_attr(feature = "arbitrary", derive(Arbitrary))] +pub struct StringM(Vec); + +/// `write_utf8_lossy` is a modified copy of the Rust stdlib docs examples here: +/// +fn write_utf8_lossy(f: &mut impl core::fmt::Write, mut input: &[u8]) -> core::fmt::Result { + loop { + match core::str::from_utf8(input) { + Ok(valid) => { + write!(f, "{}", valid)?; + break; + } + Err(error) => { + let (valid, after_valid) = input.split_at(error.valid_up_to()); + write!(f, "{}", core::str::from_utf8(valid).unwrap())?; + write!(f, "\u{FFFD}")?; + + if let Some(invalid_sequence_length) = error.error_len() { + input = &after_valid[invalid_sequence_length..]; + } else { + break; + } + } + } + } + Ok(()) +} + +impl core::fmt::Display for StringM { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + #[cfg(feature = "alloc")] + let v = &self.0; + #[cfg(not(feature = "alloc"))] + let v = self.0; + write_utf8_lossy(f, v)?; + Ok(()) + } +} + +impl core::fmt::Debug for StringM { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + #[cfg(feature = "alloc")] + let v = &self.0; + #[cfg(not(feature = "alloc"))] + let v = self.0; + write!(f, "StringM(")?; + write_utf8_lossy(f, v)?; + write!(f, ")")?; + Ok(()) + } +} + +#[cfg(feature = "alloc")] +impl core::str::FromStr for StringM { + type Err = Error; + fn from_str(s: &str) -> core::result::Result { + s.try_into() + } +} + +impl Deref for StringM { + type Target = Vec; fn deref(&self) -> &Self::Target { &self.0 } } -impl Default for VecM { +impl Default for StringM { fn default() -> Self { Self(Vec::default()) } } -impl VecM { +impl StringM { pub const MAX_LEN: usize = { MAX as usize }; #[must_use] @@ -694,25 +1504,25 @@ impl VecM { } #[must_use] - pub fn as_vec(&self) -> &Vec { + pub fn as_vec(&self) -> &Vec { self.as_ref() } } -impl VecM { +impl StringM { #[must_use] #[cfg(feature = "alloc")] - pub fn to_vec(&self) -> Vec { + pub fn to_vec(&self) -> Vec { self.into() } #[must_use] - pub fn into_vec(self) -> Vec { + pub fn into_vec(self) -> Vec { self.into() } } -impl VecM { +impl StringM { #[cfg(feature = "alloc")] pub fn to_string(&self) -> Result { self.try_into() @@ -736,120 +1546,85 @@ impl VecM { } } -impl VecM { - #[must_use] - pub fn to_option(&self) -> Option { - if self.len() > 0 { - Some(self.0[0].clone()) - } else { - None - } - } -} - -#[cfg(not(feature = "alloc"))] -impl From> for Option { - #[must_use] - fn from(v: VecM) -> Self { - v.to_option() - } -} - -#[cfg(feature = "alloc")] -impl VecM { - #[must_use] - pub fn into_option(mut self) -> Option { - self.0.drain(..).next() - } -} - -#[cfg(feature = "alloc")] -impl From> for Option { - #[must_use] - fn from(v: VecM) -> Self { - v.into_option() - } -} - -impl TryFrom> for VecM { +impl TryFrom> for StringM { type Error = Error; - fn try_from(v: Vec) -> Result { + fn try_from(v: Vec) -> Result { let len: u32 = v.len().try_into().map_err(|_| Error::LengthExceedsMax)?; if len <= MAX { - Ok(VecM(v)) + Ok(StringM(v)) } else { Err(Error::LengthExceedsMax) } } } -impl From> for Vec { +impl From> for Vec { #[must_use] - fn from(v: VecM) -> Self { + fn from(v: StringM) -> Self { v.0 } } #[cfg(feature = "alloc")] -impl From<&VecM> for Vec { +impl From<&StringM> for Vec { #[must_use] - fn from(v: &VecM) -> Self { + fn from(v: &StringM) -> Self { v.0.clone() } } -impl AsRef> for VecM { +impl AsRef> for StringM { #[must_use] - fn as_ref(&self) -> &Vec { + fn as_ref(&self) -> &Vec { &self.0 } } #[cfg(feature = "alloc")] -impl TryFrom<&Vec> for VecM { +impl TryFrom<&Vec> for StringM { type Error = Error; - fn try_from(v: &Vec) -> Result { + fn try_from(v: &Vec) -> Result { v.as_slice().try_into() } } #[cfg(feature = "alloc")] -impl TryFrom<&[T]> for VecM { +impl TryFrom<&[u8]> for StringM { type Error = Error; - fn try_from(v: &[T]) -> Result { + fn try_from(v: &[u8]) -> Result { let len: u32 = v.len().try_into().map_err(|_| Error::LengthExceedsMax)?; if len <= MAX { - Ok(VecM(v.to_vec())) + Ok(StringM(v.to_vec())) } else { Err(Error::LengthExceedsMax) } } } -impl AsRef<[T]> for VecM { +impl AsRef<[u8]> for StringM { #[cfg(feature = "alloc")] #[must_use] - fn as_ref(&self) -> &[T] { + fn as_ref(&self) -> &[u8] { self.0.as_ref() } #[cfg(not(feature = "alloc"))] #[must_use] - fn as_ref(&self) -> &[T] { + fn as_ref(&self) -> &[u8] { self.0 } } #[cfg(feature = "alloc")] -impl TryFrom<[T; N]> for VecM { +impl TryFrom<[u8; N]> for StringM { type Error = Error; - fn try_from(v: [T; N]) -> Result { + fn try_from(v: [u8; N]) -> Result { let len: u32 = v.len().try_into().map_err(|_| Error::LengthExceedsMax)?; if len <= MAX { - Ok(VecM(v.to_vec())) + Ok(StringM(v.to_vec())) } else { Err(Error::LengthExceedsMax) } @@ -857,23 +1632,23 @@ impl TryFrom<[T; N]> for VecM } #[cfg(feature = "alloc")] -impl TryFrom> for [T; N] { - type Error = VecM; +impl TryFrom> for [u8; N] { + type Error = StringM; - fn try_from(v: VecM) -> core::result::Result { - let s: [T; N] = v.0.try_into().map_err(|v: Vec| VecM::(v))?; + fn try_from(v: StringM) -> core::result::Result { + let s: [u8; N] = v.0.try_into().map_err(StringM::)?; Ok(s) } } #[cfg(feature = "alloc")] -impl TryFrom<&[T; N]> for VecM { +impl TryFrom<&[u8; N]> for StringM { type Error = Error; - fn try_from(v: &[T; N]) -> Result { + fn try_from(v: &[u8; N]) -> Result { let len: u32 = v.len().try_into().map_err(|_| Error::LengthExceedsMax)?; if len <= MAX { - Ok(VecM(v.to_vec())) + Ok(StringM(v.to_vec())) } else { Err(Error::LengthExceedsMax) } @@ -881,13 +1656,13 @@ impl TryFrom<&[T; N]> for VecM } #[cfg(not(feature = "alloc"))] -impl TryFrom<&'static [T; N]> for VecM { +impl TryFrom<&'static [u8; N]> for StringM { type Error = Error; - fn try_from(v: &'static [T; N]) -> Result { + fn try_from(v: &'static [u8; N]) -> Result { let len: u32 = v.len().try_into().map_err(|_| Error::LengthExceedsMax)?; if len <= MAX { - Ok(VecM(v)) + Ok(StringM(v)) } else { Err(Error::LengthExceedsMax) } @@ -895,13 +1670,13 @@ impl TryFrom<&'static [T; N]> for VecM } #[cfg(feature = "alloc")] -impl TryFrom<&String> for VecM { +impl TryFrom<&String> for StringM { type Error = Error; fn try_from(v: &String) -> Result { let len: u32 = v.len().try_into().map_err(|_| Error::LengthExceedsMax)?; if len <= MAX { - Ok(VecM(v.as_bytes().to_vec())) + Ok(StringM(v.as_bytes().to_vec())) } else { Err(Error::LengthExceedsMax) } @@ -909,13 +1684,13 @@ impl TryFrom<&String> for VecM { } #[cfg(feature = "alloc")] -impl TryFrom for VecM { +impl TryFrom for StringM { type Error = Error; fn try_from(v: String) -> Result { let len: u32 = v.len().try_into().map_err(|_| Error::LengthExceedsMax)?; if len <= MAX { - Ok(VecM(v.into())) + Ok(StringM(v.into())) } else { Err(Error::LengthExceedsMax) } @@ -923,31 +1698,31 @@ impl TryFrom for VecM { } #[cfg(feature = "alloc")] -impl TryFrom> for String { +impl TryFrom> for String { type Error = Error; - fn try_from(v: VecM) -> Result { + fn try_from(v: StringM) -> Result { Ok(String::from_utf8(v.0)?) } } #[cfg(feature = "alloc")] -impl TryFrom<&VecM> for String { +impl TryFrom<&StringM> for String { type Error = Error; - fn try_from(v: &VecM) -> Result { + fn try_from(v: &StringM) -> Result { Ok(core::str::from_utf8(v.as_ref())?.to_owned()) } } #[cfg(feature = "alloc")] -impl TryFrom<&str> for VecM { +impl TryFrom<&str> for StringM { type Error = Error; fn try_from(v: &str) -> Result { let len: u32 = v.len().try_into().map_err(|_| Error::LengthExceedsMax)?; if len <= MAX { - Ok(VecM(v.into())) + Ok(StringM(v.into())) } else { Err(Error::LengthExceedsMax) } @@ -955,28 +1730,28 @@ impl TryFrom<&str> for VecM { } #[cfg(not(feature = "alloc"))] -impl TryFrom<&'static str> for VecM { +impl TryFrom<&'static str> for StringM { type Error = Error; fn try_from(v: &'static str) -> Result { let len: u32 = v.len().try_into().map_err(|_| Error::LengthExceedsMax)?; if len <= MAX { - Ok(VecM(v.as_bytes())) + Ok(StringM(v.as_bytes())) } else { Err(Error::LengthExceedsMax) } } } -impl<'a, const MAX: u32> TryFrom<&'a VecM> for &'a str { +impl<'a, const MAX: u32> TryFrom<&'a StringM> for &'a str { type Error = Error; - fn try_from(v: &'a VecM) -> Result { + fn try_from(v: &'a StringM) -> Result { Ok(core::str::from_utf8(v.as_ref())?) } } -impl ReadXdr for VecM { +impl ReadXdr for StringM { #[cfg(feature = "std")] fn read_xdr(r: &mut impl Read) -> Result { let len: u32 = u32::read_xdr(r)?; @@ -993,11 +1768,11 @@ impl ReadXdr for VecM { return Err(Error::NonZeroPadding); } - Ok(VecM(vec)) + Ok(StringM(vec)) } } -impl WriteXdr for VecM { +impl WriteXdr for StringM { #[cfg(feature = "std")] fn write_xdr(&self, w: &mut impl Write) -> Result<()> { let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; @@ -1011,38 +1786,6 @@ impl WriteXdr for VecM { } } -impl ReadXdr for VecM { - #[cfg(feature = "std")] - fn read_xdr(r: &mut impl Read) -> Result { - let len = u32::read_xdr(r)?; - if len > MAX { - return Err(Error::LengthExceedsMax); - } - - let mut vec = Vec::with_capacity(len as usize); - for _ in 0..len { - let t = T::read_xdr(r)?; - vec.push(t); - } - - Ok(VecM(vec)) - } -} - -impl WriteXdr for VecM { - #[cfg(feature = "std")] - fn write_xdr(&self, w: &mut impl Write) -> Result<()> { - let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; - len.write_xdr(w)?; - - for t in &self.0 { - t.write_xdr(w)?; - } - - Ok(()) - } -} - #[cfg(all(test, feature = "std"))] mod tests { use std::io::Cursor; @@ -1202,33 +1945,33 @@ mod test { // // typedef opaque Value<>; // -#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] #[cfg_attr(feature = "arbitrary", derive(Arbitrary))] -#[derive(Default)] +#[derive(Default, Debug)] #[cfg_attr( all(feature = "serde", feature = "alloc"), derive(serde::Serialize, serde::Deserialize), serde(rename_all = "camelCase") )] -pub struct Value(pub VecM); +pub struct Value(pub BytesM); -impl From for VecM { +impl From for BytesM { #[must_use] fn from(x: Value) -> Self { x.0 } } -impl From> for Value { +impl From for Value { #[must_use] - fn from(x: VecM) -> Self { + fn from(x: BytesM) -> Self { Value(x) } } -impl AsRef> for Value { +impl AsRef for Value { #[must_use] - fn as_ref(&self) -> &VecM { + fn as_ref(&self) -> &BytesM { &self.0 } } @@ -1236,7 +1979,7 @@ impl AsRef> for Value { impl ReadXdr for Value { #[cfg(feature = "std")] fn read_xdr(r: &mut impl Read) -> Result { - let i = VecM::::read_xdr(r)?; + let i = BytesM::read_xdr(r)?; let v = Value(i); Ok(v) } @@ -1250,7 +1993,7 @@ impl WriteXdr for Value { } impl Deref for Value { - type Target = VecM; + type Target = BytesM; fn deref(&self) -> &Self::Target { &self.0 } @@ -1944,8 +2687,9 @@ impl WriteXdr for ScpQuorumSet { // // typedef PublicKey AccountID; // -#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] #[cfg_attr(feature = "arbitrary", derive(Arbitrary))] +#[derive(Debug)] #[cfg_attr( all(feature = "serde", feature = "alloc"), derive(serde::Serialize, serde::Deserialize), @@ -1994,15 +2738,43 @@ impl WriteXdr for AccountId { // // typedef opaque Thresholds[4]; // -#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] #[cfg_attr(feature = "arbitrary", derive(Arbitrary))] #[cfg_attr( all(feature = "serde", feature = "alloc"), - derive(serde::Serialize, serde::Deserialize), - serde(rename_all = "camelCase") + derive(serde_with::SerializeDisplay, serde_with::DeserializeFromStr) )] pub struct Thresholds(pub [u8; 4]); +impl core::fmt::Display for Thresholds { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + let v = &self.0; + for b in v { + write!(f, "{b:02x}")?; + } + Ok(()) + } +} + +impl core::fmt::Debug for Thresholds { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + let v = &self.0; + write!(f, "Thresholds(")?; + for b in v { + write!(f, "{b:02x}")?; + } + write!(f, ")")?; + Ok(()) + } +} + +#[cfg(feature = "alloc")] +impl core::str::FromStr for Thresholds { + type Err = Error; + fn from_str(s: &str) -> core::result::Result { + hex::decode(s).map_err(|_| Error::InvalidHex)?.try_into() + } +} impl From for [u8; 4] { #[must_use] fn from(x: Thresholds) -> Self { @@ -2081,20 +2853,21 @@ impl AsRef<[u8]> for Thresholds { // // typedef string string32<32>; // -pub type String32 = VecM; +pub type String32 = StringM<32>; // String64 is an XDR Typedef defines as: // // typedef string string64<64>; // -pub type String64 = VecM; +pub type String64 = StringM<64>; // SequenceNumber is an XDR Typedef defines as: // // typedef int64 SequenceNumber; // -#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] #[cfg_attr(feature = "arbitrary", derive(Arbitrary))] +#[derive(Debug)] #[cfg_attr( all(feature = "serde", feature = "alloc"), derive(serde::Serialize, serde::Deserialize), @@ -2143,8 +2916,9 @@ impl WriteXdr for SequenceNumber { // // typedef uint64 TimePoint; // -#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] #[cfg_attr(feature = "arbitrary", derive(Arbitrary))] +#[derive(Debug)] #[cfg_attr( all(feature = "serde", feature = "alloc"), derive(serde::Serialize, serde::Deserialize), @@ -2193,8 +2967,9 @@ impl WriteXdr for TimePoint { // // typedef uint64 Duration; // -#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] #[cfg_attr(feature = "arbitrary", derive(Arbitrary))] +#[derive(Debug)] #[cfg_attr( all(feature = "serde", feature = "alloc"), derive(serde::Serialize, serde::Deserialize), @@ -2243,33 +3018,33 @@ impl WriteXdr for Duration { // // typedef opaque DataValue<64>; // -#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] #[cfg_attr(feature = "arbitrary", derive(Arbitrary))] -#[derive(Default)] +#[derive(Default, Debug)] #[cfg_attr( all(feature = "serde", feature = "alloc"), derive(serde::Serialize, serde::Deserialize), serde(rename_all = "camelCase") )] -pub struct DataValue(pub VecM); +pub struct DataValue(pub BytesM<64>); -impl From for VecM { +impl From for BytesM<64> { #[must_use] fn from(x: DataValue) -> Self { x.0 } } -impl From> for DataValue { +impl From> for DataValue { #[must_use] - fn from(x: VecM) -> Self { + fn from(x: BytesM<64>) -> Self { DataValue(x) } } -impl AsRef> for DataValue { +impl AsRef> for DataValue { #[must_use] - fn as_ref(&self) -> &VecM { + fn as_ref(&self) -> &BytesM<64> { &self.0 } } @@ -2277,7 +3052,7 @@ impl AsRef> for DataValue { impl ReadXdr for DataValue { #[cfg(feature = "std")] fn read_xdr(r: &mut impl Read) -> Result { - let i = VecM::::read_xdr(r)?; + let i = BytesM::<64>::read_xdr(r)?; let v = DataValue(i); Ok(v) } @@ -2291,7 +3066,7 @@ impl WriteXdr for DataValue { } impl Deref for DataValue { - type Target = VecM; + type Target = BytesM<64>; fn deref(&self) -> &Self::Target { &self.0 } @@ -2343,8 +3118,9 @@ impl AsRef<[u8]> for DataValue { // // typedef Hash PoolID; // -#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] #[cfg_attr(feature = "arbitrary", derive(Arbitrary))] +#[derive(Debug)] #[cfg_attr( all(feature = "serde", feature = "alloc"), derive(serde::Serialize, serde::Deserialize), @@ -2393,15 +3169,43 @@ impl WriteXdr for PoolId { // // typedef opaque AssetCode4[4]; // -#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] #[cfg_attr(feature = "arbitrary", derive(Arbitrary))] #[cfg_attr( all(feature = "serde", feature = "alloc"), - derive(serde::Serialize, serde::Deserialize), - serde(rename_all = "camelCase") + derive(serde_with::SerializeDisplay, serde_with::DeserializeFromStr) )] pub struct AssetCode4(pub [u8; 4]); +impl core::fmt::Display for AssetCode4 { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + let v = &self.0; + for b in v { + write!(f, "{b:02x}")?; + } + Ok(()) + } +} + +impl core::fmt::Debug for AssetCode4 { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + let v = &self.0; + write!(f, "AssetCode4(")?; + for b in v { + write!(f, "{b:02x}")?; + } + write!(f, ")")?; + Ok(()) + } +} + +#[cfg(feature = "alloc")] +impl core::str::FromStr for AssetCode4 { + type Err = Error; + fn from_str(s: &str) -> core::result::Result { + hex::decode(s).map_err(|_| Error::InvalidHex)?.try_into() + } +} impl From for [u8; 4] { #[must_use] fn from(x: AssetCode4) -> Self { @@ -2480,15 +3284,43 @@ impl AsRef<[u8]> for AssetCode4 { // // typedef opaque AssetCode12[12]; // -#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] #[cfg_attr(feature = "arbitrary", derive(Arbitrary))] #[cfg_attr( all(feature = "serde", feature = "alloc"), - derive(serde::Serialize, serde::Deserialize), - serde(rename_all = "camelCase") + derive(serde_with::SerializeDisplay, serde_with::DeserializeFromStr) )] pub struct AssetCode12(pub [u8; 12]); +impl core::fmt::Display for AssetCode12 { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + let v = &self.0; + for b in v { + write!(f, "{b:02x}")?; + } + Ok(()) + } +} + +impl core::fmt::Debug for AssetCode12 { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + let v = &self.0; + write!(f, "AssetCode12(")?; + for b in v { + write!(f, "{b:02x}")?; + } + write!(f, ")")?; + Ok(()) + } +} + +#[cfg(feature = "alloc")] +impl core::str::FromStr for AssetCode12 { + type Err = Error; + fn from_str(s: &str) -> core::result::Result { + hex::decode(s).map_err(|_| Error::InvalidHex)?.try_into() + } +} impl From for [u8; 12] { #[must_use] fn from(x: AssetCode12) -> Self { @@ -3481,8 +4313,9 @@ pub const MAX_SIGNERS: u64 = 20; // // typedef AccountID* SponsorshipDescriptor; // -#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] #[cfg_attr(feature = "arbitrary", derive(Arbitrary))] +#[derive(Debug)] #[cfg_attr( all(feature = "serde", feature = "alloc"), derive(serde::Serialize, serde::Deserialize), @@ -4026,7 +4859,7 @@ pub struct AccountEntry { pub num_sub_entries: u32, pub inflation_dest: Option, pub flags: u32, - pub home_domain: VecM, + pub home_domain: StringM<32>, pub thresholds: Thresholds, pub signers: VecM, pub ext: AccountEntryExt, @@ -4042,7 +4875,7 @@ impl ReadXdr for AccountEntry { num_sub_entries: u32::read_xdr(r)?, inflation_dest: Option::::read_xdr(r)?, flags: u32::read_xdr(r)?, - home_domain: VecM::::read_xdr(r)?, + home_domain: StringM::<32>::read_xdr(r)?, thresholds: Thresholds::read_xdr(r)?, signers: VecM::::read_xdr(r)?, ext: AccountEntryExt::read_xdr(r)?, @@ -5293,7 +6126,7 @@ impl WriteXdr for DataEntryExt { )] pub struct DataEntry { pub account_id: AccountId, - pub data_name: VecM, + pub data_name: StringM<64>, pub data_value: DataValue, pub ext: DataEntryExt, } @@ -5303,7 +6136,7 @@ impl ReadXdr for DataEntry { fn read_xdr(r: &mut impl Read) -> Result { Ok(Self { account_id: AccountId::read_xdr(r)?, - data_name: VecM::::read_xdr(r)?, + data_name: StringM::<64>::read_xdr(r)?, data_value: DataValue::read_xdr(r)?, ext: DataEntryExt::read_xdr(r)?, }) @@ -7270,7 +8103,7 @@ impl WriteXdr for LedgerKeyOffer { )] pub struct LedgerKeyData { pub account_id: AccountId, - pub data_name: VecM, + pub data_name: StringM<64>, } impl ReadXdr for LedgerKeyData { @@ -7278,7 +8111,7 @@ impl ReadXdr for LedgerKeyData { fn read_xdr(r: &mut impl Read) -> Result { Ok(Self { account_id: AccountId::read_xdr(r)?, - data_name: VecM::::read_xdr(r)?, + data_name: StringM::<64>::read_xdr(r)?, }) } } @@ -7680,33 +8513,33 @@ impl WriteXdr for EnvelopeType { // // typedef opaque UpgradeType<128>; // -#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] #[cfg_attr(feature = "arbitrary", derive(Arbitrary))] -#[derive(Default)] +#[derive(Default, Debug)] #[cfg_attr( all(feature = "serde", feature = "alloc"), derive(serde::Serialize, serde::Deserialize), serde(rename_all = "camelCase") )] -pub struct UpgradeType(pub VecM); +pub struct UpgradeType(pub BytesM<128>); -impl From for VecM { +impl From for BytesM<128> { #[must_use] fn from(x: UpgradeType) -> Self { x.0 } } -impl From> for UpgradeType { +impl From> for UpgradeType { #[must_use] - fn from(x: VecM) -> Self { + fn from(x: BytesM<128>) -> Self { UpgradeType(x) } } -impl AsRef> for UpgradeType { +impl AsRef> for UpgradeType { #[must_use] - fn as_ref(&self) -> &VecM { + fn as_ref(&self) -> &BytesM<128> { &self.0 } } @@ -7714,7 +8547,7 @@ impl AsRef> for UpgradeType { impl ReadXdr for UpgradeType { #[cfg(feature = "std")] fn read_xdr(r: &mut impl Read) -> Result { - let i = VecM::::read_xdr(r)?; + let i = BytesM::<128>::read_xdr(r)?; let v = UpgradeType(i); Ok(v) } @@ -7728,7 +8561,7 @@ impl WriteXdr for UpgradeType { } impl Deref for UpgradeType { - type Target = VecM; + type Target = BytesM<128>; fn deref(&self) -> &Self::Target { &self.0 } @@ -10598,9 +11431,9 @@ impl WriteXdr for LedgerEntryChange { // // typedef LedgerEntryChange LedgerEntryChanges<>; // -#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] #[cfg_attr(feature = "arbitrary", derive(Arbitrary))] -#[derive(Default)] +#[derive(Default, Debug)] #[cfg_attr( all(feature = "serde", feature = "alloc"), derive(serde::Serialize, serde::Deserialize), @@ -11358,7 +12191,7 @@ impl WriteXdr for ErrorCode { )] pub struct SError { pub code: ErrorCode, - pub msg: VecM, + pub msg: StringM<100>, } impl ReadXdr for SError { @@ -11366,7 +12199,7 @@ impl ReadXdr for SError { fn read_xdr(r: &mut impl Read) -> Result { Ok(Self { code: ErrorCode::read_xdr(r)?, - msg: VecM::::read_xdr(r)?, + msg: StringM::<100>::read_xdr(r)?, }) } } @@ -11485,7 +12318,7 @@ pub struct Hello { pub overlay_version: u32, pub overlay_min_version: u32, pub network_id: Hash, - pub version_str: VecM, + pub version_str: StringM<100>, pub listening_port: i32, pub peer_id: NodeId, pub cert: AuthCert, @@ -11500,7 +12333,7 @@ impl ReadXdr for Hello { overlay_version: u32::read_xdr(r)?, overlay_min_version: u32::read_xdr(r)?, network_id: Hash::read_xdr(r)?, - version_str: VecM::::read_xdr(r)?, + version_str: StringM::<100>::read_xdr(r)?, listening_port: i32::read_xdr(r)?, peer_id: NodeId::read_xdr(r)?, cert: AuthCert::read_xdr(r)?, @@ -12260,33 +13093,33 @@ impl WriteXdr for SignedSurveyRequestMessage { // // typedef opaque EncryptedBody<64000>; // -#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] #[cfg_attr(feature = "arbitrary", derive(Arbitrary))] -#[derive(Default)] +#[derive(Default, Debug)] #[cfg_attr( all(feature = "serde", feature = "alloc"), derive(serde::Serialize, serde::Deserialize), serde(rename_all = "camelCase") )] -pub struct EncryptedBody(pub VecM); +pub struct EncryptedBody(pub BytesM<64000>); -impl From for VecM { +impl From for BytesM<64000> { #[must_use] fn from(x: EncryptedBody) -> Self { x.0 } } -impl From> for EncryptedBody { +impl From> for EncryptedBody { #[must_use] - fn from(x: VecM) -> Self { + fn from(x: BytesM<64000>) -> Self { EncryptedBody(x) } } -impl AsRef> for EncryptedBody { +impl AsRef> for EncryptedBody { #[must_use] - fn as_ref(&self) -> &VecM { + fn as_ref(&self) -> &BytesM<64000> { &self.0 } } @@ -12294,7 +13127,7 @@ impl AsRef> for EncryptedBody { impl ReadXdr for EncryptedBody { #[cfg(feature = "std")] fn read_xdr(r: &mut impl Read) -> Result { - let i = VecM::::read_xdr(r)?; + let i = BytesM::<64000>::read_xdr(r)?; let v = EncryptedBody(i); Ok(v) } @@ -12308,7 +13141,7 @@ impl WriteXdr for EncryptedBody { } impl Deref for EncryptedBody { - type Target = VecM; + type Target = BytesM<64000>; fn deref(&self) -> &Self::Target { &self.0 } @@ -12478,7 +13311,7 @@ impl WriteXdr for SignedSurveyResponseMessage { )] pub struct PeerStats { pub id: NodeId, - pub version_str: VecM, + pub version_str: StringM<100>, pub messages_read: u64, pub messages_written: u64, pub bytes_read: u64, @@ -12499,7 +13332,7 @@ impl ReadXdr for PeerStats { fn read_xdr(r: &mut impl Read) -> Result { Ok(Self { id: NodeId::read_xdr(r)?, - version_str: VecM::::read_xdr(r)?, + version_str: StringM::<100>::read_xdr(r)?, messages_read: u64::read_xdr(r)?, messages_written: u64::read_xdr(r)?, bytes_read: u64::read_xdr(r)?, @@ -12543,9 +13376,9 @@ impl WriteXdr for PeerStats { // // typedef PeerStats PeerStatList<25>; // -#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] #[cfg_attr(feature = "arbitrary", derive(Arbitrary))] -#[derive(Default)] +#[derive(Default, Debug)] #[cfg_attr( all(feature = "serde", feature = "alloc"), derive(serde::Serialize, serde::Deserialize), @@ -12793,9 +13626,9 @@ pub const TX_ADVERT_VECTOR_MAX_SIZE: u64 = 1000; // // typedef Hash TxAdvertVector; // -#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] #[cfg_attr(feature = "arbitrary", derive(Arbitrary))] -#[derive(Default)] +#[derive(Default, Debug)] #[cfg_attr( all(feature = "serde", feature = "alloc"), derive(serde::Serialize, serde::Deserialize), @@ -12934,9 +13767,9 @@ pub const TX_DEMAND_VECTOR_MAX_SIZE: u64 = 1000; // // typedef Hash TxDemandVector; // -#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] #[cfg_attr(feature = "arbitrary", derive(Arbitrary))] -#[derive(Default)] +#[derive(Default, Debug)] #[cfg_attr( all(feature = "serde", feature = "alloc"), derive(serde::Serialize, serde::Deserialize), @@ -14390,7 +15223,7 @@ pub struct SetOptionsOp { pub low_threshold: Option, pub med_threshold: Option, pub high_threshold: Option, - pub home_domain: Option>, + pub home_domain: Option>, pub signer: Option, } @@ -14405,7 +15238,7 @@ impl ReadXdr for SetOptionsOp { low_threshold: Option::::read_xdr(r)?, med_threshold: Option::::read_xdr(r)?, high_threshold: Option::::read_xdr(r)?, - home_domain: Option::>::read_xdr(r)?, + home_domain: Option::>::read_xdr(r)?, signer: Option::::read_xdr(r)?, }) } @@ -14655,7 +15488,7 @@ impl WriteXdr for AllowTrustOp { serde(rename_all = "camelCase") )] pub struct ManageDataOp { - pub data_name: VecM, + pub data_name: StringM<64>, pub data_value: Option, } @@ -14663,7 +15496,7 @@ impl ReadXdr for ManageDataOp { #[cfg(feature = "std")] fn read_xdr(r: &mut impl Read) -> Result { Ok(Self { - data_name: VecM::::read_xdr(r)?, + data_name: StringM::<64>::read_xdr(r)?, data_value: Option::::read_xdr(r)?, }) } @@ -16081,7 +16914,7 @@ impl WriteXdr for MemoType { #[allow(clippy::large_enum_variant)] pub enum Memo { None, - Text(VecM), + Text(StringM<28>), Id(u64), Hash(Hash), Return(Hash), @@ -16155,7 +16988,7 @@ impl ReadXdr for Memo { #[allow(clippy::match_same_arms, clippy::match_wildcard_for_single_variants)] let v = match dv { MemoType::None => Self::None, - MemoType::Text => Self::Text(VecM::::read_xdr(r)?), + MemoType::Text => Self::Text(StringM::<28>::read_xdr(r)?), MemoType::Id => Self::Id(u64::read_xdr(r)?), MemoType::Hash => Self::Hash(Hash::read_xdr(r)?), MemoType::Return => Self::Return(Hash::read_xdr(r)?), @@ -26696,15 +27529,43 @@ impl WriteXdr for TransactionResult { // // typedef opaque Hash[32]; // -#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] #[cfg_attr(feature = "arbitrary", derive(Arbitrary))] #[cfg_attr( all(feature = "serde", feature = "alloc"), - derive(serde::Serialize, serde::Deserialize), - serde(rename_all = "camelCase") + derive(serde_with::SerializeDisplay, serde_with::DeserializeFromStr) )] pub struct Hash(pub [u8; 32]); +impl core::fmt::Display for Hash { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + let v = &self.0; + for b in v { + write!(f, "{b:02x}")?; + } + Ok(()) + } +} + +impl core::fmt::Debug for Hash { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + let v = &self.0; + write!(f, "Hash(")?; + for b in v { + write!(f, "{b:02x}")?; + } + write!(f, ")")?; + Ok(()) + } +} + +#[cfg(feature = "alloc")] +impl core::str::FromStr for Hash { + type Err = Error; + fn from_str(s: &str) -> core::result::Result { + hex::decode(s).map_err(|_| Error::InvalidHex)?.try_into() + } +} impl From for [u8; 32] { #[must_use] fn from(x: Hash) -> Self { @@ -26783,15 +27644,43 @@ impl AsRef<[u8]> for Hash { // // typedef opaque uint256[32]; // -#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] #[cfg_attr(feature = "arbitrary", derive(Arbitrary))] #[cfg_attr( all(feature = "serde", feature = "alloc"), - derive(serde::Serialize, serde::Deserialize), - serde(rename_all = "camelCase") + derive(serde_with::SerializeDisplay, serde_with::DeserializeFromStr) )] pub struct Uint256(pub [u8; 32]); +impl core::fmt::Display for Uint256 { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + let v = &self.0; + for b in v { + write!(f, "{b:02x}")?; + } + Ok(()) + } +} + +impl core::fmt::Debug for Uint256 { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + let v = &self.0; + write!(f, "Uint256(")?; + for b in v { + write!(f, "{b:02x}")?; + } + write!(f, ")")?; + Ok(()) + } +} + +#[cfg(feature = "alloc")] +impl core::str::FromStr for Uint256 { + type Err = Error; + fn from_str(s: &str) -> core::result::Result { + hex::decode(s).map_err(|_| Error::InvalidHex)?.try_into() + } +} impl From for [u8; 32] { #[must_use] fn from(x: Uint256) -> Self { @@ -27432,7 +28321,7 @@ impl WriteXdr for PublicKey { )] pub struct SignerKeyEd25519SignedPayload { pub ed25519: Uint256, - pub payload: VecM, + pub payload: BytesM<64>, } impl ReadXdr for SignerKeyEd25519SignedPayload { @@ -27440,7 +28329,7 @@ impl ReadXdr for SignerKeyEd25519SignedPayload { fn read_xdr(r: &mut impl Read) -> Result { Ok(Self { ed25519: Uint256::read_xdr(r)?, - payload: VecM::::read_xdr(r)?, + payload: BytesM::<64>::read_xdr(r)?, }) } } @@ -27589,33 +28478,33 @@ impl WriteXdr for SignerKey { // // typedef opaque Signature<64>; // -#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] #[cfg_attr(feature = "arbitrary", derive(Arbitrary))] -#[derive(Default)] +#[derive(Default, Debug)] #[cfg_attr( all(feature = "serde", feature = "alloc"), derive(serde::Serialize, serde::Deserialize), serde(rename_all = "camelCase") )] -pub struct Signature(pub VecM); +pub struct Signature(pub BytesM<64>); -impl From for VecM { +impl From for BytesM<64> { #[must_use] fn from(x: Signature) -> Self { x.0 } } -impl From> for Signature { +impl From> for Signature { #[must_use] - fn from(x: VecM) -> Self { + fn from(x: BytesM<64>) -> Self { Signature(x) } } -impl AsRef> for Signature { +impl AsRef> for Signature { #[must_use] - fn as_ref(&self) -> &VecM { + fn as_ref(&self) -> &BytesM<64> { &self.0 } } @@ -27623,7 +28512,7 @@ impl AsRef> for Signature { impl ReadXdr for Signature { #[cfg(feature = "std")] fn read_xdr(r: &mut impl Read) -> Result { - let i = VecM::::read_xdr(r)?; + let i = BytesM::<64>::read_xdr(r)?; let v = Signature(i); Ok(v) } @@ -27637,7 +28526,7 @@ impl WriteXdr for Signature { } impl Deref for Signature { - type Target = VecM; + type Target = BytesM<64>; fn deref(&self) -> &Self::Target { &self.0 } @@ -27689,15 +28578,43 @@ impl AsRef<[u8]> for Signature { // // typedef opaque SignatureHint[4]; // -#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] #[cfg_attr(feature = "arbitrary", derive(Arbitrary))] #[cfg_attr( all(feature = "serde", feature = "alloc"), - derive(serde::Serialize, serde::Deserialize), - serde(rename_all = "camelCase") + derive(serde_with::SerializeDisplay, serde_with::DeserializeFromStr) )] pub struct SignatureHint(pub [u8; 4]); +impl core::fmt::Display for SignatureHint { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + let v = &self.0; + for b in v { + write!(f, "{b:02x}")?; + } + Ok(()) + } +} + +impl core::fmt::Debug for SignatureHint { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + let v = &self.0; + write!(f, "SignatureHint(")?; + for b in v { + write!(f, "{b:02x}")?; + } + write!(f, ")")?; + Ok(()) + } +} + +#[cfg(feature = "alloc")] +impl core::str::FromStr for SignatureHint { + type Err = Error; + fn from_str(s: &str) -> core::result::Result { + hex::decode(s).map_err(|_| Error::InvalidHex)?.try_into() + } +} impl From for [u8; 4] { #[must_use] fn from(x: SignatureHint) -> Self { @@ -27776,8 +28693,9 @@ impl AsRef<[u8]> for SignatureHint { // // typedef PublicKey NodeID; // -#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] #[cfg_attr(feature = "arbitrary", derive(Arbitrary))] +#[derive(Debug)] #[cfg_attr( all(feature = "serde", feature = "alloc"), derive(serde::Serialize, serde::Deserialize), diff --git a/src/next.rs b/src/next.rs index c55e3a73..6d09e738 100644 --- a/src/next.rs +++ b/src/next.rs @@ -104,6 +104,8 @@ pub enum Error { LengthMismatch, NonZeroPadding, Utf8Error(core::str::Utf8Error), + #[cfg(feature = "alloc")] + InvalidHex, #[cfg(feature = "std")] Io(io::Error), } @@ -144,6 +146,8 @@ impl fmt::Display for Error { Error::LengthMismatch => write!(f, "xdr value length does not match"), Error::NonZeroPadding => write!(f, "xdr padding contains non-zero bytes"), Error::Utf8Error(e) => write!(f, "{}", e), + #[cfg(feature = "alloc")] + Error::InvalidHex => write!(f, "hex invalid"), #[cfg(feature = "std")] Error::Io(e) => write!(f, "{}", e), } @@ -672,6 +676,8 @@ impl WriteXdr for [T; N] { } } +// VecM ------------------------------------------------------------------------ + #[cfg(feature = "alloc")] #[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] @@ -1058,6 +1064,743 @@ impl WriteXdr for VecM { } } +// BytesM ------------------------------------------------------------------------ + +#[cfg(feature = "alloc")] +#[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[cfg_attr( + feature = "serde", + derive(serde_with::SerializeDisplay, serde_with::DeserializeFromStr) +)] +#[cfg_attr(feature = "arbitrary", derive(Arbitrary))] +pub struct BytesM(Vec); + +#[cfg(not(feature = "alloc"))] +#[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[cfg_attr(feature = "arbitrary", derive(Arbitrary))] +pub struct BytesM(Vec); + +impl core::fmt::Display for BytesM { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + #[cfg(feature = "alloc")] + let v = &self.0; + #[cfg(not(feature = "alloc"))] + let v = self.0; + for b in v { + write!(f, "{b:02x}")?; + } + Ok(()) + } +} + +impl core::fmt::Debug for BytesM { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + #[cfg(feature = "alloc")] + let v = &self.0; + #[cfg(not(feature = "alloc"))] + let v = self.0; + write!(f, "BytesM(")?; + for b in v { + write!(f, "{b:02x}")?; + } + write!(f, ")")?; + Ok(()) + } +} + +#[cfg(feature = "alloc")] +impl core::str::FromStr for BytesM { + type Err = Error; + fn from_str(s: &str) -> core::result::Result { + hex::decode(s).map_err(|_| Error::InvalidHex)?.try_into() + } +} + +impl Deref for BytesM { + type Target = Vec; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl Default for BytesM { + fn default() -> Self { + Self(Vec::default()) + } +} + +impl BytesM { + pub const MAX_LEN: usize = { MAX as usize }; + + #[must_use] + #[allow(clippy::unused_self)] + pub fn max_len(&self) -> usize { + Self::MAX_LEN + } + + #[must_use] + pub fn as_vec(&self) -> &Vec { + self.as_ref() + } +} + +impl BytesM { + #[must_use] + #[cfg(feature = "alloc")] + pub fn to_vec(&self) -> Vec { + self.into() + } + + #[must_use] + pub fn into_vec(self) -> Vec { + self.into() + } +} + +impl BytesM { + #[cfg(feature = "alloc")] + pub fn to_string(&self) -> Result { + self.try_into() + } + + #[cfg(feature = "alloc")] + pub fn into_string(self) -> Result { + self.try_into() + } + + #[cfg(feature = "alloc")] + #[must_use] + pub fn to_string_lossy(&self) -> String { + String::from_utf8_lossy(&self.0).into_owned() + } + + #[cfg(feature = "alloc")] + #[must_use] + pub fn into_string_lossy(self) -> String { + String::from_utf8_lossy(&self.0).into_owned() + } +} + +impl TryFrom> for BytesM { + type Error = Error; + + fn try_from(v: Vec) -> Result { + let len: u32 = v.len().try_into().map_err(|_| Error::LengthExceedsMax)?; + if len <= MAX { + Ok(BytesM(v)) + } else { + Err(Error::LengthExceedsMax) + } + } +} + +impl From> for Vec { + #[must_use] + fn from(v: BytesM) -> Self { + v.0 + } +} + +#[cfg(feature = "alloc")] +impl From<&BytesM> for Vec { + #[must_use] + fn from(v: &BytesM) -> Self { + v.0.clone() + } +} + +impl AsRef> for BytesM { + #[must_use] + fn as_ref(&self) -> &Vec { + &self.0 + } +} + +#[cfg(feature = "alloc")] +impl TryFrom<&Vec> for BytesM { + type Error = Error; + + fn try_from(v: &Vec) -> Result { + v.as_slice().try_into() + } +} + +#[cfg(feature = "alloc")] +impl TryFrom<&[u8]> for BytesM { + type Error = Error; + + fn try_from(v: &[u8]) -> Result { + let len: u32 = v.len().try_into().map_err(|_| Error::LengthExceedsMax)?; + if len <= MAX { + Ok(BytesM(v.to_vec())) + } else { + Err(Error::LengthExceedsMax) + } + } +} + +impl AsRef<[u8]> for BytesM { + #[cfg(feature = "alloc")] + #[must_use] + fn as_ref(&self) -> &[u8] { + self.0.as_ref() + } + #[cfg(not(feature = "alloc"))] + #[must_use] + fn as_ref(&self) -> &[u8] { + self.0 + } +} + +#[cfg(feature = "alloc")] +impl TryFrom<[u8; N]> for BytesM { + type Error = Error; + + fn try_from(v: [u8; N]) -> Result { + let len: u32 = v.len().try_into().map_err(|_| Error::LengthExceedsMax)?; + if len <= MAX { + Ok(BytesM(v.to_vec())) + } else { + Err(Error::LengthExceedsMax) + } + } +} + +#[cfg(feature = "alloc")] +impl TryFrom> for [u8; N] { + type Error = BytesM; + + fn try_from(v: BytesM) -> core::result::Result { + let s: [u8; N] = v.0.try_into().map_err(BytesM::)?; + Ok(s) + } +} + +#[cfg(feature = "alloc")] +impl TryFrom<&[u8; N]> for BytesM { + type Error = Error; + + fn try_from(v: &[u8; N]) -> Result { + let len: u32 = v.len().try_into().map_err(|_| Error::LengthExceedsMax)?; + if len <= MAX { + Ok(BytesM(v.to_vec())) + } else { + Err(Error::LengthExceedsMax) + } + } +} + +#[cfg(not(feature = "alloc"))] +impl TryFrom<&'static [u8; N]> for BytesM { + type Error = Error; + + fn try_from(v: &'static [u8; N]) -> Result { + let len: u32 = v.len().try_into().map_err(|_| Error::LengthExceedsMax)?; + if len <= MAX { + Ok(BytesM(v)) + } else { + Err(Error::LengthExceedsMax) + } + } +} + +#[cfg(feature = "alloc")] +impl TryFrom<&String> for BytesM { + type Error = Error; + + fn try_from(v: &String) -> Result { + let len: u32 = v.len().try_into().map_err(|_| Error::LengthExceedsMax)?; + if len <= MAX { + Ok(BytesM(v.as_bytes().to_vec())) + } else { + Err(Error::LengthExceedsMax) + } + } +} + +#[cfg(feature = "alloc")] +impl TryFrom for BytesM { + type Error = Error; + + fn try_from(v: String) -> Result { + let len: u32 = v.len().try_into().map_err(|_| Error::LengthExceedsMax)?; + if len <= MAX { + Ok(BytesM(v.into())) + } else { + Err(Error::LengthExceedsMax) + } + } +} + +#[cfg(feature = "alloc")] +impl TryFrom> for String { + type Error = Error; + + fn try_from(v: BytesM) -> Result { + Ok(String::from_utf8(v.0)?) + } +} + +#[cfg(feature = "alloc")] +impl TryFrom<&BytesM> for String { + type Error = Error; + + fn try_from(v: &BytesM) -> Result { + Ok(core::str::from_utf8(v.as_ref())?.to_owned()) + } +} + +#[cfg(feature = "alloc")] +impl TryFrom<&str> for BytesM { + type Error = Error; + + fn try_from(v: &str) -> Result { + let len: u32 = v.len().try_into().map_err(|_| Error::LengthExceedsMax)?; + if len <= MAX { + Ok(BytesM(v.into())) + } else { + Err(Error::LengthExceedsMax) + } + } +} + +#[cfg(not(feature = "alloc"))] +impl TryFrom<&'static str> for BytesM { + type Error = Error; + + fn try_from(v: &'static str) -> Result { + let len: u32 = v.len().try_into().map_err(|_| Error::LengthExceedsMax)?; + if len <= MAX { + Ok(BytesM(v.as_bytes())) + } else { + Err(Error::LengthExceedsMax) + } + } +} + +impl<'a, const MAX: u32> TryFrom<&'a BytesM> for &'a str { + type Error = Error; + + fn try_from(v: &'a BytesM) -> Result { + Ok(core::str::from_utf8(v.as_ref())?) + } +} + +impl ReadXdr for BytesM { + #[cfg(feature = "std")] + fn read_xdr(r: &mut impl Read) -> Result { + let len: u32 = u32::read_xdr(r)?; + if len > MAX { + return Err(Error::LengthExceedsMax); + } + + let mut vec = vec![0u8; len as usize]; + r.read_exact(&mut vec)?; + + let pad = &mut [0u8; 3][..pad_len(len as usize)]; + r.read_exact(pad)?; + if pad.iter().any(|b| *b != 0) { + return Err(Error::NonZeroPadding); + } + + Ok(BytesM(vec)) + } +} + +impl WriteXdr for BytesM { + #[cfg(feature = "std")] + fn write_xdr(&self, w: &mut impl Write) -> Result<()> { + let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; + len.write_xdr(w)?; + + w.write_all(&self.0)?; + + w.write_all(&[0u8; 3][..pad_len(len as usize)])?; + + Ok(()) + } +} + +// StringM ------------------------------------------------------------------------ + +#[cfg(feature = "alloc")] +#[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[cfg_attr( + feature = "serde", + derive(serde_with::SerializeDisplay, serde_with::DeserializeFromStr) +)] +#[cfg_attr(feature = "arbitrary", derive(Arbitrary))] +pub struct StringM(Vec); + +#[cfg(not(feature = "alloc"))] +#[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[cfg_attr(feature = "arbitrary", derive(Arbitrary))] +pub struct StringM(Vec); + +/// `write_utf8_lossy` is a modified copy of the Rust stdlib docs examples here: +/// +fn write_utf8_lossy(f: &mut impl core::fmt::Write, mut input: &[u8]) -> core::fmt::Result { + loop { + match core::str::from_utf8(input) { + Ok(valid) => { + write!(f, "{}", valid)?; + break; + } + Err(error) => { + let (valid, after_valid) = input.split_at(error.valid_up_to()); + write!(f, "{}", core::str::from_utf8(valid).unwrap())?; + write!(f, "\u{FFFD}")?; + + if let Some(invalid_sequence_length) = error.error_len() { + input = &after_valid[invalid_sequence_length..]; + } else { + break; + } + } + } + } + Ok(()) +} + +impl core::fmt::Display for StringM { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + #[cfg(feature = "alloc")] + let v = &self.0; + #[cfg(not(feature = "alloc"))] + let v = self.0; + write_utf8_lossy(f, v)?; + Ok(()) + } +} + +impl core::fmt::Debug for StringM { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + #[cfg(feature = "alloc")] + let v = &self.0; + #[cfg(not(feature = "alloc"))] + let v = self.0; + write!(f, "StringM(")?; + write_utf8_lossy(f, v)?; + write!(f, ")")?; + Ok(()) + } +} + +#[cfg(feature = "alloc")] +impl core::str::FromStr for StringM { + type Err = Error; + fn from_str(s: &str) -> core::result::Result { + s.try_into() + } +} + +impl Deref for StringM { + type Target = Vec; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl Default for StringM { + fn default() -> Self { + Self(Vec::default()) + } +} + +impl StringM { + pub const MAX_LEN: usize = { MAX as usize }; + + #[must_use] + #[allow(clippy::unused_self)] + pub fn max_len(&self) -> usize { + Self::MAX_LEN + } + + #[must_use] + pub fn as_vec(&self) -> &Vec { + self.as_ref() + } +} + +impl StringM { + #[must_use] + #[cfg(feature = "alloc")] + pub fn to_vec(&self) -> Vec { + self.into() + } + + #[must_use] + pub fn into_vec(self) -> Vec { + self.into() + } +} + +impl StringM { + #[cfg(feature = "alloc")] + pub fn to_string(&self) -> Result { + self.try_into() + } + + #[cfg(feature = "alloc")] + pub fn into_string(self) -> Result { + self.try_into() + } + + #[cfg(feature = "alloc")] + #[must_use] + pub fn to_string_lossy(&self) -> String { + String::from_utf8_lossy(&self.0).into_owned() + } + + #[cfg(feature = "alloc")] + #[must_use] + pub fn into_string_lossy(self) -> String { + String::from_utf8_lossy(&self.0).into_owned() + } +} + +impl TryFrom> for StringM { + type Error = Error; + + fn try_from(v: Vec) -> Result { + let len: u32 = v.len().try_into().map_err(|_| Error::LengthExceedsMax)?; + if len <= MAX { + Ok(StringM(v)) + } else { + Err(Error::LengthExceedsMax) + } + } +} + +impl From> for Vec { + #[must_use] + fn from(v: StringM) -> Self { + v.0 + } +} + +#[cfg(feature = "alloc")] +impl From<&StringM> for Vec { + #[must_use] + fn from(v: &StringM) -> Self { + v.0.clone() + } +} + +impl AsRef> for StringM { + #[must_use] + fn as_ref(&self) -> &Vec { + &self.0 + } +} + +#[cfg(feature = "alloc")] +impl TryFrom<&Vec> for StringM { + type Error = Error; + + fn try_from(v: &Vec) -> Result { + v.as_slice().try_into() + } +} + +#[cfg(feature = "alloc")] +impl TryFrom<&[u8]> for StringM { + type Error = Error; + + fn try_from(v: &[u8]) -> Result { + let len: u32 = v.len().try_into().map_err(|_| Error::LengthExceedsMax)?; + if len <= MAX { + Ok(StringM(v.to_vec())) + } else { + Err(Error::LengthExceedsMax) + } + } +} + +impl AsRef<[u8]> for StringM { + #[cfg(feature = "alloc")] + #[must_use] + fn as_ref(&self) -> &[u8] { + self.0.as_ref() + } + #[cfg(not(feature = "alloc"))] + #[must_use] + fn as_ref(&self) -> &[u8] { + self.0 + } +} + +#[cfg(feature = "alloc")] +impl TryFrom<[u8; N]> for StringM { + type Error = Error; + + fn try_from(v: [u8; N]) -> Result { + let len: u32 = v.len().try_into().map_err(|_| Error::LengthExceedsMax)?; + if len <= MAX { + Ok(StringM(v.to_vec())) + } else { + Err(Error::LengthExceedsMax) + } + } +} + +#[cfg(feature = "alloc")] +impl TryFrom> for [u8; N] { + type Error = StringM; + + fn try_from(v: StringM) -> core::result::Result { + let s: [u8; N] = v.0.try_into().map_err(StringM::)?; + Ok(s) + } +} + +#[cfg(feature = "alloc")] +impl TryFrom<&[u8; N]> for StringM { + type Error = Error; + + fn try_from(v: &[u8; N]) -> Result { + let len: u32 = v.len().try_into().map_err(|_| Error::LengthExceedsMax)?; + if len <= MAX { + Ok(StringM(v.to_vec())) + } else { + Err(Error::LengthExceedsMax) + } + } +} + +#[cfg(not(feature = "alloc"))] +impl TryFrom<&'static [u8; N]> for StringM { + type Error = Error; + + fn try_from(v: &'static [u8; N]) -> Result { + let len: u32 = v.len().try_into().map_err(|_| Error::LengthExceedsMax)?; + if len <= MAX { + Ok(StringM(v)) + } else { + Err(Error::LengthExceedsMax) + } + } +} + +#[cfg(feature = "alloc")] +impl TryFrom<&String> for StringM { + type Error = Error; + + fn try_from(v: &String) -> Result { + let len: u32 = v.len().try_into().map_err(|_| Error::LengthExceedsMax)?; + if len <= MAX { + Ok(StringM(v.as_bytes().to_vec())) + } else { + Err(Error::LengthExceedsMax) + } + } +} + +#[cfg(feature = "alloc")] +impl TryFrom for StringM { + type Error = Error; + + fn try_from(v: String) -> Result { + let len: u32 = v.len().try_into().map_err(|_| Error::LengthExceedsMax)?; + if len <= MAX { + Ok(StringM(v.into())) + } else { + Err(Error::LengthExceedsMax) + } + } +} + +#[cfg(feature = "alloc")] +impl TryFrom> for String { + type Error = Error; + + fn try_from(v: StringM) -> Result { + Ok(String::from_utf8(v.0)?) + } +} + +#[cfg(feature = "alloc")] +impl TryFrom<&StringM> for String { + type Error = Error; + + fn try_from(v: &StringM) -> Result { + Ok(core::str::from_utf8(v.as_ref())?.to_owned()) + } +} + +#[cfg(feature = "alloc")] +impl TryFrom<&str> for StringM { + type Error = Error; + + fn try_from(v: &str) -> Result { + let len: u32 = v.len().try_into().map_err(|_| Error::LengthExceedsMax)?; + if len <= MAX { + Ok(StringM(v.into())) + } else { + Err(Error::LengthExceedsMax) + } + } +} + +#[cfg(not(feature = "alloc"))] +impl TryFrom<&'static str> for StringM { + type Error = Error; + + fn try_from(v: &'static str) -> Result { + let len: u32 = v.len().try_into().map_err(|_| Error::LengthExceedsMax)?; + if len <= MAX { + Ok(StringM(v.as_bytes())) + } else { + Err(Error::LengthExceedsMax) + } + } +} + +impl<'a, const MAX: u32> TryFrom<&'a StringM> for &'a str { + type Error = Error; + + fn try_from(v: &'a StringM) -> Result { + Ok(core::str::from_utf8(v.as_ref())?) + } +} + +impl ReadXdr for StringM { + #[cfg(feature = "std")] + fn read_xdr(r: &mut impl Read) -> Result { + let len: u32 = u32::read_xdr(r)?; + if len > MAX { + return Err(Error::LengthExceedsMax); + } + + let mut vec = vec![0u8; len as usize]; + r.read_exact(&mut vec)?; + + let pad = &mut [0u8; 3][..pad_len(len as usize)]; + r.read_exact(pad)?; + if pad.iter().any(|b| *b != 0) { + return Err(Error::NonZeroPadding); + } + + Ok(StringM(vec)) + } +} + +impl WriteXdr for StringM { + #[cfg(feature = "std")] + fn write_xdr(&self, w: &mut impl Write) -> Result<()> { + let len: u32 = self.len().try_into().map_err(|_| Error::LengthExceedsMax)?; + len.write_xdr(w)?; + + w.write_all(&self.0)?; + + w.write_all(&[0u8; 3][..pad_len(len as usize)])?; + + Ok(()) + } +} + #[cfg(all(test, feature = "std"))] mod tests { use std::io::Cursor; @@ -1217,33 +1960,33 @@ mod test { // // typedef opaque Value<>; // -#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] #[cfg_attr(feature = "arbitrary", derive(Arbitrary))] -#[derive(Default)] +#[derive(Default, Debug)] #[cfg_attr( all(feature = "serde", feature = "alloc"), derive(serde::Serialize, serde::Deserialize), serde(rename_all = "camelCase") )] -pub struct Value(pub VecM); +pub struct Value(pub BytesM); -impl From for VecM { +impl From for BytesM { #[must_use] fn from(x: Value) -> Self { x.0 } } -impl From> for Value { +impl From for Value { #[must_use] - fn from(x: VecM) -> Self { + fn from(x: BytesM) -> Self { Value(x) } } -impl AsRef> for Value { +impl AsRef for Value { #[must_use] - fn as_ref(&self) -> &VecM { + fn as_ref(&self) -> &BytesM { &self.0 } } @@ -1251,7 +1994,7 @@ impl AsRef> for Value { impl ReadXdr for Value { #[cfg(feature = "std")] fn read_xdr(r: &mut impl Read) -> Result { - let i = VecM::::read_xdr(r)?; + let i = BytesM::read_xdr(r)?; let v = Value(i); Ok(v) } @@ -1265,7 +2008,7 @@ impl WriteXdr for Value { } impl Deref for Value { - type Target = VecM; + type Target = BytesM; fn deref(&self) -> &Self::Target { &self.0 } @@ -1959,15 +2702,43 @@ impl WriteXdr for ScpQuorumSet { // // typedef opaque Thresholds[4]; // -#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] #[cfg_attr(feature = "arbitrary", derive(Arbitrary))] #[cfg_attr( all(feature = "serde", feature = "alloc"), - derive(serde::Serialize, serde::Deserialize), - serde(rename_all = "camelCase") + derive(serde_with::SerializeDisplay, serde_with::DeserializeFromStr) )] pub struct Thresholds(pub [u8; 4]); +impl core::fmt::Display for Thresholds { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + let v = &self.0; + for b in v { + write!(f, "{b:02x}")?; + } + Ok(()) + } +} + +impl core::fmt::Debug for Thresholds { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + let v = &self.0; + write!(f, "Thresholds(")?; + for b in v { + write!(f, "{b:02x}")?; + } + write!(f, ")")?; + Ok(()) + } +} + +#[cfg(feature = "alloc")] +impl core::str::FromStr for Thresholds { + type Err = Error; + fn from_str(s: &str) -> core::result::Result { + hex::decode(s).map_err(|_| Error::InvalidHex)?.try_into() + } +} impl From for [u8; 4] { #[must_use] fn from(x: Thresholds) -> Self { @@ -2046,20 +2817,21 @@ impl AsRef<[u8]> for Thresholds { // // typedef string string32<32>; // -pub type String32 = VecM; +pub type String32 = StringM<32>; // String64 is an XDR Typedef defines as: // // typedef string string64<64>; // -pub type String64 = VecM; +pub type String64 = StringM<64>; // SequenceNumber is an XDR Typedef defines as: // // typedef int64 SequenceNumber; // -#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] #[cfg_attr(feature = "arbitrary", derive(Arbitrary))] +#[derive(Debug)] #[cfg_attr( all(feature = "serde", feature = "alloc"), derive(serde::Serialize, serde::Deserialize), @@ -2108,8 +2880,9 @@ impl WriteXdr for SequenceNumber { // // typedef uint64 TimePoint; // -#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] #[cfg_attr(feature = "arbitrary", derive(Arbitrary))] +#[derive(Debug)] #[cfg_attr( all(feature = "serde", feature = "alloc"), derive(serde::Serialize, serde::Deserialize), @@ -2158,8 +2931,9 @@ impl WriteXdr for TimePoint { // // typedef uint64 Duration; // -#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] #[cfg_attr(feature = "arbitrary", derive(Arbitrary))] +#[derive(Debug)] #[cfg_attr( all(feature = "serde", feature = "alloc"), derive(serde::Serialize, serde::Deserialize), @@ -2208,33 +2982,33 @@ impl WriteXdr for Duration { // // typedef opaque DataValue<64>; // -#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] #[cfg_attr(feature = "arbitrary", derive(Arbitrary))] -#[derive(Default)] +#[derive(Default, Debug)] #[cfg_attr( all(feature = "serde", feature = "alloc"), derive(serde::Serialize, serde::Deserialize), serde(rename_all = "camelCase") )] -pub struct DataValue(pub VecM); +pub struct DataValue(pub BytesM<64>); -impl From for VecM { +impl From for BytesM<64> { #[must_use] fn from(x: DataValue) -> Self { x.0 } } -impl From> for DataValue { +impl From> for DataValue { #[must_use] - fn from(x: VecM) -> Self { + fn from(x: BytesM<64>) -> Self { DataValue(x) } } -impl AsRef> for DataValue { +impl AsRef> for DataValue { #[must_use] - fn as_ref(&self) -> &VecM { + fn as_ref(&self) -> &BytesM<64> { &self.0 } } @@ -2242,7 +3016,7 @@ impl AsRef> for DataValue { impl ReadXdr for DataValue { #[cfg(feature = "std")] fn read_xdr(r: &mut impl Read) -> Result { - let i = VecM::::read_xdr(r)?; + let i = BytesM::<64>::read_xdr(r)?; let v = DataValue(i); Ok(v) } @@ -2256,7 +3030,7 @@ impl WriteXdr for DataValue { } impl Deref for DataValue { - type Target = VecM; + type Target = BytesM<64>; fn deref(&self) -> &Self::Target { &self.0 } @@ -2308,8 +3082,9 @@ impl AsRef<[u8]> for DataValue { // // typedef Hash PoolID; // -#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] #[cfg_attr(feature = "arbitrary", derive(Arbitrary))] +#[derive(Debug)] #[cfg_attr( all(feature = "serde", feature = "alloc"), derive(serde::Serialize, serde::Deserialize), @@ -2358,15 +3133,43 @@ impl WriteXdr for PoolId { // // typedef opaque AssetCode4[4]; // -#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] #[cfg_attr(feature = "arbitrary", derive(Arbitrary))] #[cfg_attr( all(feature = "serde", feature = "alloc"), - derive(serde::Serialize, serde::Deserialize), - serde(rename_all = "camelCase") + derive(serde_with::SerializeDisplay, serde_with::DeserializeFromStr) )] pub struct AssetCode4(pub [u8; 4]); +impl core::fmt::Display for AssetCode4 { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + let v = &self.0; + for b in v { + write!(f, "{b:02x}")?; + } + Ok(()) + } +} + +impl core::fmt::Debug for AssetCode4 { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + let v = &self.0; + write!(f, "AssetCode4(")?; + for b in v { + write!(f, "{b:02x}")?; + } + write!(f, ")")?; + Ok(()) + } +} + +#[cfg(feature = "alloc")] +impl core::str::FromStr for AssetCode4 { + type Err = Error; + fn from_str(s: &str) -> core::result::Result { + hex::decode(s).map_err(|_| Error::InvalidHex)?.try_into() + } +} impl From for [u8; 4] { #[must_use] fn from(x: AssetCode4) -> Self { @@ -2445,15 +3248,43 @@ impl AsRef<[u8]> for AssetCode4 { // // typedef opaque AssetCode12[12]; // -#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] #[cfg_attr(feature = "arbitrary", derive(Arbitrary))] #[cfg_attr( all(feature = "serde", feature = "alloc"), - derive(serde::Serialize, serde::Deserialize), - serde(rename_all = "camelCase") + derive(serde_with::SerializeDisplay, serde_with::DeserializeFromStr) )] pub struct AssetCode12(pub [u8; 12]); +impl core::fmt::Display for AssetCode12 { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + let v = &self.0; + for b in v { + write!(f, "{b:02x}")?; + } + Ok(()) + } +} + +impl core::fmt::Debug for AssetCode12 { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + let v = &self.0; + write!(f, "AssetCode12(")?; + for b in v { + write!(f, "{b:02x}")?; + } + write!(f, ")")?; + Ok(()) + } +} + +#[cfg(feature = "alloc")] +impl core::str::FromStr for AssetCode12 { + type Err = Error; + fn from_str(s: &str) -> core::result::Result { + hex::decode(s).map_err(|_| Error::InvalidHex)?.try_into() + } +} impl From for [u8; 12] { #[must_use] fn from(x: AssetCode12) -> Self { @@ -3458,8 +4289,9 @@ pub const MAX_SIGNERS: u64 = 20; // // typedef AccountID* SponsorshipDescriptor; // -#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] #[cfg_attr(feature = "arbitrary", derive(Arbitrary))] +#[derive(Debug)] #[cfg_attr( all(feature = "serde", feature = "alloc"), derive(serde::Serialize, serde::Deserialize), @@ -4003,7 +4835,7 @@ pub struct AccountEntry { pub num_sub_entries: u32, pub inflation_dest: Option, pub flags: u32, - pub home_domain: VecM, + pub home_domain: StringM<32>, pub thresholds: Thresholds, pub signers: VecM, pub ext: AccountEntryExt, @@ -4019,7 +4851,7 @@ impl ReadXdr for AccountEntry { num_sub_entries: u32::read_xdr(r)?, inflation_dest: Option::::read_xdr(r)?, flags: u32::read_xdr(r)?, - home_domain: VecM::::read_xdr(r)?, + home_domain: StringM::<32>::read_xdr(r)?, thresholds: Thresholds::read_xdr(r)?, signers: VecM::::read_xdr(r)?, ext: AccountEntryExt::read_xdr(r)?, @@ -5270,7 +6102,7 @@ impl WriteXdr for DataEntryExt { )] pub struct DataEntry { pub account_id: AccountId, - pub data_name: VecM, + pub data_name: StringM<64>, pub data_value: DataValue, pub ext: DataEntryExt, } @@ -5280,7 +6112,7 @@ impl ReadXdr for DataEntry { fn read_xdr(r: &mut impl Read) -> Result { Ok(Self { account_id: AccountId::read_xdr(r)?, - data_name: VecM::::read_xdr(r)?, + data_name: StringM::<64>::read_xdr(r)?, data_value: DataValue::read_xdr(r)?, ext: DataEntryExt::read_xdr(r)?, }) @@ -7740,7 +8572,7 @@ impl WriteXdr for LedgerKeyOffer { )] pub struct LedgerKeyData { pub account_id: AccountId, - pub data_name: VecM, + pub data_name: StringM<64>, } impl ReadXdr for LedgerKeyData { @@ -7748,7 +8580,7 @@ impl ReadXdr for LedgerKeyData { fn read_xdr(r: &mut impl Read) -> Result { Ok(Self { account_id: AccountId::read_xdr(r)?, - data_name: VecM::::read_xdr(r)?, + data_name: StringM::<64>::read_xdr(r)?, }) } } @@ -8277,33 +9109,33 @@ impl WriteXdr for EnvelopeType { // // typedef opaque UpgradeType<128>; // -#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] #[cfg_attr(feature = "arbitrary", derive(Arbitrary))] -#[derive(Default)] +#[derive(Default, Debug)] #[cfg_attr( all(feature = "serde", feature = "alloc"), derive(serde::Serialize, serde::Deserialize), serde(rename_all = "camelCase") )] -pub struct UpgradeType(pub VecM); +pub struct UpgradeType(pub BytesM<128>); -impl From for VecM { +impl From for BytesM<128> { #[must_use] fn from(x: UpgradeType) -> Self { x.0 } } -impl From> for UpgradeType { +impl From> for UpgradeType { #[must_use] - fn from(x: VecM) -> Self { + fn from(x: BytesM<128>) -> Self { UpgradeType(x) } } -impl AsRef> for UpgradeType { +impl AsRef> for UpgradeType { #[must_use] - fn as_ref(&self) -> &VecM { + fn as_ref(&self) -> &BytesM<128> { &self.0 } } @@ -8311,7 +9143,7 @@ impl AsRef> for UpgradeType { impl ReadXdr for UpgradeType { #[cfg(feature = "std")] fn read_xdr(r: &mut impl Read) -> Result { - let i = VecM::::read_xdr(r)?; + let i = BytesM::<128>::read_xdr(r)?; let v = UpgradeType(i); Ok(v) } @@ -8325,7 +9157,7 @@ impl WriteXdr for UpgradeType { } impl Deref for UpgradeType { - type Target = VecM; + type Target = BytesM<128>; fn deref(&self) -> &Self::Target { &self.0 } @@ -11510,9 +12342,9 @@ impl WriteXdr for LedgerEntryChange { // // typedef LedgerEntryChange LedgerEntryChanges<>; // -#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] #[cfg_attr(feature = "arbitrary", derive(Arbitrary))] -#[derive(Default)] +#[derive(Default, Debug)] #[cfg_attr( all(feature = "serde", feature = "alloc"), derive(serde::Serialize, serde::Deserialize), @@ -12744,7 +13576,7 @@ impl WriteXdr for ErrorCode { )] pub struct SError { pub code: ErrorCode, - pub msg: VecM, + pub msg: StringM<100>, } impl ReadXdr for SError { @@ -12752,7 +13584,7 @@ impl ReadXdr for SError { fn read_xdr(r: &mut impl Read) -> Result { Ok(Self { code: ErrorCode::read_xdr(r)?, - msg: VecM::::read_xdr(r)?, + msg: StringM::<100>::read_xdr(r)?, }) } } @@ -12871,7 +13703,7 @@ pub struct Hello { pub overlay_version: u32, pub overlay_min_version: u32, pub network_id: Hash, - pub version_str: VecM, + pub version_str: StringM<100>, pub listening_port: i32, pub peer_id: NodeId, pub cert: AuthCert, @@ -12886,7 +13718,7 @@ impl ReadXdr for Hello { overlay_version: u32::read_xdr(r)?, overlay_min_version: u32::read_xdr(r)?, network_id: Hash::read_xdr(r)?, - version_str: VecM::::read_xdr(r)?, + version_str: StringM::<100>::read_xdr(r)?, listening_port: i32::read_xdr(r)?, peer_id: NodeId::read_xdr(r)?, cert: AuthCert::read_xdr(r)?, @@ -13646,33 +14478,33 @@ impl WriteXdr for SignedSurveyRequestMessage { // // typedef opaque EncryptedBody<64000>; // -#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] #[cfg_attr(feature = "arbitrary", derive(Arbitrary))] -#[derive(Default)] +#[derive(Default, Debug)] #[cfg_attr( all(feature = "serde", feature = "alloc"), derive(serde::Serialize, serde::Deserialize), serde(rename_all = "camelCase") )] -pub struct EncryptedBody(pub VecM); +pub struct EncryptedBody(pub BytesM<64000>); -impl From for VecM { +impl From for BytesM<64000> { #[must_use] fn from(x: EncryptedBody) -> Self { x.0 } } -impl From> for EncryptedBody { +impl From> for EncryptedBody { #[must_use] - fn from(x: VecM) -> Self { + fn from(x: BytesM<64000>) -> Self { EncryptedBody(x) } } -impl AsRef> for EncryptedBody { +impl AsRef> for EncryptedBody { #[must_use] - fn as_ref(&self) -> &VecM { + fn as_ref(&self) -> &BytesM<64000> { &self.0 } } @@ -13680,7 +14512,7 @@ impl AsRef> for EncryptedBody { impl ReadXdr for EncryptedBody { #[cfg(feature = "std")] fn read_xdr(r: &mut impl Read) -> Result { - let i = VecM::::read_xdr(r)?; + let i = BytesM::<64000>::read_xdr(r)?; let v = EncryptedBody(i); Ok(v) } @@ -13694,7 +14526,7 @@ impl WriteXdr for EncryptedBody { } impl Deref for EncryptedBody { - type Target = VecM; + type Target = BytesM<64000>; fn deref(&self) -> &Self::Target { &self.0 } @@ -13864,7 +14696,7 @@ impl WriteXdr for SignedSurveyResponseMessage { )] pub struct PeerStats { pub id: NodeId, - pub version_str: VecM, + pub version_str: StringM<100>, pub messages_read: u64, pub messages_written: u64, pub bytes_read: u64, @@ -13885,7 +14717,7 @@ impl ReadXdr for PeerStats { fn read_xdr(r: &mut impl Read) -> Result { Ok(Self { id: NodeId::read_xdr(r)?, - version_str: VecM::::read_xdr(r)?, + version_str: StringM::<100>::read_xdr(r)?, messages_read: u64::read_xdr(r)?, messages_written: u64::read_xdr(r)?, bytes_read: u64::read_xdr(r)?, @@ -13929,9 +14761,9 @@ impl WriteXdr for PeerStats { // // typedef PeerStats PeerStatList<25>; // -#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] #[cfg_attr(feature = "arbitrary", derive(Arbitrary))] -#[derive(Default)] +#[derive(Default, Debug)] #[cfg_attr( all(feature = "serde", feature = "alloc"), derive(serde::Serialize, serde::Deserialize), @@ -14083,9 +14915,9 @@ pub const TX_ADVERT_VECTOR_MAX_SIZE: u64 = 1000; // // typedef Hash TxAdvertVector; // -#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] #[cfg_attr(feature = "arbitrary", derive(Arbitrary))] -#[derive(Default)] +#[derive(Default, Debug)] #[cfg_attr( all(feature = "serde", feature = "alloc"), derive(serde::Serialize, serde::Deserialize), @@ -14224,9 +15056,9 @@ pub const TX_DEMAND_VECTOR_MAX_SIZE: u64 = 1000; // // typedef Hash TxDemandVector; // -#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] #[cfg_attr(feature = "arbitrary", derive(Arbitrary))] -#[derive(Default)] +#[derive(Default, Debug)] #[cfg_attr( all(feature = "serde", feature = "alloc"), derive(serde::Serialize, serde::Deserialize), @@ -15821,7 +16653,7 @@ pub struct SetOptionsOp { pub low_threshold: Option, pub med_threshold: Option, pub high_threshold: Option, - pub home_domain: Option>, + pub home_domain: Option>, pub signer: Option, } @@ -15836,7 +16668,7 @@ impl ReadXdr for SetOptionsOp { low_threshold: Option::::read_xdr(r)?, med_threshold: Option::::read_xdr(r)?, high_threshold: Option::::read_xdr(r)?, - home_domain: Option::>::read_xdr(r)?, + home_domain: Option::>::read_xdr(r)?, signer: Option::::read_xdr(r)?, }) } @@ -16086,7 +16918,7 @@ impl WriteXdr for AllowTrustOp { serde(rename_all = "camelCase") )] pub struct ManageDataOp { - pub data_name: VecM, + pub data_name: StringM<64>, pub data_value: Option, } @@ -16094,7 +16926,7 @@ impl ReadXdr for ManageDataOp { #[cfg(feature = "std")] fn read_xdr(r: &mut impl Read) -> Result { Ok(Self { - data_name: VecM::::read_xdr(r)?, + data_name: StringM::<64>::read_xdr(r)?, data_value: Option::::read_xdr(r)?, }) } @@ -17873,7 +18705,7 @@ impl WriteXdr for MemoType { #[allow(clippy::large_enum_variant)] pub enum Memo { None, - Text(VecM), + Text(StringM<28>), Id(u64), Hash(Hash), Return(Hash), @@ -17947,7 +18779,7 @@ impl ReadXdr for Memo { #[allow(clippy::match_same_arms, clippy::match_wildcard_for_single_variants)] let v = match dv { MemoType::None => Self::None, - MemoType::Text => Self::Text(VecM::::read_xdr(r)?), + MemoType::Text => Self::Text(StringM::<28>::read_xdr(r)?), MemoType::Id => Self::Id(u64::read_xdr(r)?), MemoType::Hash => Self::Hash(Hash::read_xdr(r)?), MemoType::Return => Self::Return(Hash::read_xdr(r)?), @@ -28723,15 +29555,43 @@ impl WriteXdr for TransactionResult { // // typedef opaque Hash[32]; // -#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] #[cfg_attr(feature = "arbitrary", derive(Arbitrary))] #[cfg_attr( all(feature = "serde", feature = "alloc"), - derive(serde::Serialize, serde::Deserialize), - serde(rename_all = "camelCase") + derive(serde_with::SerializeDisplay, serde_with::DeserializeFromStr) )] pub struct Hash(pub [u8; 32]); +impl core::fmt::Display for Hash { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + let v = &self.0; + for b in v { + write!(f, "{b:02x}")?; + } + Ok(()) + } +} + +impl core::fmt::Debug for Hash { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + let v = &self.0; + write!(f, "Hash(")?; + for b in v { + write!(f, "{b:02x}")?; + } + write!(f, ")")?; + Ok(()) + } +} + +#[cfg(feature = "alloc")] +impl core::str::FromStr for Hash { + type Err = Error; + fn from_str(s: &str) -> core::result::Result { + hex::decode(s).map_err(|_| Error::InvalidHex)?.try_into() + } +} impl From for [u8; 32] { #[must_use] fn from(x: Hash) -> Self { @@ -28810,15 +29670,43 @@ impl AsRef<[u8]> for Hash { // // typedef opaque uint256[32]; // -#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] #[cfg_attr(feature = "arbitrary", derive(Arbitrary))] #[cfg_attr( all(feature = "serde", feature = "alloc"), - derive(serde::Serialize, serde::Deserialize), - serde(rename_all = "camelCase") + derive(serde_with::SerializeDisplay, serde_with::DeserializeFromStr) )] pub struct Uint256(pub [u8; 32]); +impl core::fmt::Display for Uint256 { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + let v = &self.0; + for b in v { + write!(f, "{b:02x}")?; + } + Ok(()) + } +} + +impl core::fmt::Debug for Uint256 { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + let v = &self.0; + write!(f, "Uint256(")?; + for b in v { + write!(f, "{b:02x}")?; + } + write!(f, ")")?; + Ok(()) + } +} + +#[cfg(feature = "alloc")] +impl core::str::FromStr for Uint256 { + type Err = Error; + fn from_str(s: &str) -> core::result::Result { + hex::decode(s).map_err(|_| Error::InvalidHex)?.try_into() + } +} impl From for [u8; 32] { #[must_use] fn from(x: Uint256) -> Self { @@ -29459,7 +30347,7 @@ impl WriteXdr for PublicKey { )] pub struct SignerKeyEd25519SignedPayload { pub ed25519: Uint256, - pub payload: VecM, + pub payload: BytesM<64>, } impl ReadXdr for SignerKeyEd25519SignedPayload { @@ -29467,7 +30355,7 @@ impl ReadXdr for SignerKeyEd25519SignedPayload { fn read_xdr(r: &mut impl Read) -> Result { Ok(Self { ed25519: Uint256::read_xdr(r)?, - payload: VecM::::read_xdr(r)?, + payload: BytesM::<64>::read_xdr(r)?, }) } } @@ -29616,33 +30504,33 @@ impl WriteXdr for SignerKey { // // typedef opaque Signature<64>; // -#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] #[cfg_attr(feature = "arbitrary", derive(Arbitrary))] -#[derive(Default)] +#[derive(Default, Debug)] #[cfg_attr( all(feature = "serde", feature = "alloc"), derive(serde::Serialize, serde::Deserialize), serde(rename_all = "camelCase") )] -pub struct Signature(pub VecM); +pub struct Signature(pub BytesM<64>); -impl From for VecM { +impl From for BytesM<64> { #[must_use] fn from(x: Signature) -> Self { x.0 } } -impl From> for Signature { +impl From> for Signature { #[must_use] - fn from(x: VecM) -> Self { + fn from(x: BytesM<64>) -> Self { Signature(x) } } -impl AsRef> for Signature { +impl AsRef> for Signature { #[must_use] - fn as_ref(&self) -> &VecM { + fn as_ref(&self) -> &BytesM<64> { &self.0 } } @@ -29650,7 +30538,7 @@ impl AsRef> for Signature { impl ReadXdr for Signature { #[cfg(feature = "std")] fn read_xdr(r: &mut impl Read) -> Result { - let i = VecM::::read_xdr(r)?; + let i = BytesM::<64>::read_xdr(r)?; let v = Signature(i); Ok(v) } @@ -29664,7 +30552,7 @@ impl WriteXdr for Signature { } impl Deref for Signature { - type Target = VecM; + type Target = BytesM<64>; fn deref(&self) -> &Self::Target { &self.0 } @@ -29716,15 +30604,43 @@ impl AsRef<[u8]> for Signature { // // typedef opaque SignatureHint[4]; // -#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] #[cfg_attr(feature = "arbitrary", derive(Arbitrary))] #[cfg_attr( all(feature = "serde", feature = "alloc"), - derive(serde::Serialize, serde::Deserialize), - serde(rename_all = "camelCase") + derive(serde_with::SerializeDisplay, serde_with::DeserializeFromStr) )] pub struct SignatureHint(pub [u8; 4]); +impl core::fmt::Display for SignatureHint { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + let v = &self.0; + for b in v { + write!(f, "{b:02x}")?; + } + Ok(()) + } +} + +impl core::fmt::Debug for SignatureHint { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + let v = &self.0; + write!(f, "SignatureHint(")?; + for b in v { + write!(f, "{b:02x}")?; + } + write!(f, ")")?; + Ok(()) + } +} + +#[cfg(feature = "alloc")] +impl core::str::FromStr for SignatureHint { + type Err = Error; + fn from_str(s: &str) -> core::result::Result { + hex::decode(s).map_err(|_| Error::InvalidHex)?.try_into() + } +} impl From for [u8; 4] { #[must_use] fn from(x: SignatureHint) -> Self { @@ -29803,8 +30719,9 @@ impl AsRef<[u8]> for SignatureHint { // // typedef PublicKey NodeID; // -#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] #[cfg_attr(feature = "arbitrary", derive(Arbitrary))] +#[derive(Debug)] #[cfg_attr( all(feature = "serde", feature = "alloc"), derive(serde::Serialize, serde::Deserialize), @@ -29853,8 +30770,9 @@ impl WriteXdr for NodeId { // // typedef PublicKey AccountID; // -#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] #[cfg_attr(feature = "arbitrary", derive(Arbitrary))] +#[derive(Debug)] #[cfg_attr( all(feature = "serde", feature = "alloc"), derive(serde::Serialize, serde::Deserialize), @@ -30043,7 +30961,7 @@ impl WriteXdr for HmacSha256Mac { // // typedef string SCSymbol<10>; // -pub type ScSymbol = VecM; +pub type ScSymbol = StringM<10>; // ScValType is an XDR Enum defines as: // @@ -31614,7 +32532,7 @@ pub enum ScVal { I32(i32), Static(ScStatic), Object(Option), - Symbol(VecM), + Symbol(StringM<10>), Bitset(u64), Status(ScStatus), } @@ -31702,7 +32620,7 @@ impl ReadXdr for ScVal { ScValType::I32 => Self::I32(i32::read_xdr(r)?), ScValType::Static => Self::Static(ScStatic::read_xdr(r)?), ScValType::Object => Self::Object(Option::::read_xdr(r)?), - ScValType::Symbol => Self::Symbol(VecM::::read_xdr(r)?), + ScValType::Symbol => Self::Symbol(StringM::<10>::read_xdr(r)?), ScValType::Bitset => Self::Bitset(u64::read_xdr(r)?), ScValType::Status => Self::Status(ScStatus::read_xdr(r)?), #[allow(unreachable_patterns)] @@ -31926,9 +32844,9 @@ pub const SCVAL_LIMIT: u64 = 256000; // // typedef SCVal SCVec; // -#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] #[cfg_attr(feature = "arbitrary", derive(Arbitrary))] -#[derive(Default)] +#[derive(Default, Debug)] #[cfg_attr( all(feature = "serde", feature = "alloc"), derive(serde::Serialize, serde::Deserialize), @@ -32026,9 +32944,9 @@ impl AsRef<[ScVal]> for ScVec { // // typedef SCMapEntry SCMap; // -#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] #[cfg_attr(feature = "arbitrary", derive(Arbitrary))] -#[derive(Default)] +#[derive(Default, Debug)] #[cfg_attr( all(feature = "serde", feature = "alloc"), derive(serde::Serialize, serde::Deserialize), @@ -32248,8 +33166,8 @@ impl WriteXdr for ScNumSign { #[allow(clippy::large_enum_variant)] pub enum ScBigInt { Zero, - Positive(VecM), - Negative(VecM), + Positive(BytesM<256000>), + Negative(BytesM<256000>), } impl ScBigInt { @@ -32311,8 +33229,8 @@ impl ReadXdr for ScBigInt { #[allow(clippy::match_same_arms, clippy::match_wildcard_for_single_variants)] let v = match dv { ScNumSign::Zero => Self::Zero, - ScNumSign::Positive => Self::Positive(VecM::::read_xdr(r)?), - ScNumSign::Negative => Self::Negative(VecM::::read_xdr(r)?), + ScNumSign::Positive => Self::Positive(BytesM::<256000>::read_xdr(r)?), + ScNumSign::Negative => Self::Negative(BytesM::<256000>::read_xdr(r)?), #[allow(unreachable_patterns)] _ => return Err(Error::Invalid), }; @@ -32454,7 +33372,7 @@ impl WriteXdr for ScContractCodeType { )] #[allow(clippy::large_enum_variant)] pub enum ScContractCode { - Wasm(VecM), + Wasm(BytesM<256000>), Token, } @@ -32514,7 +33432,7 @@ impl ReadXdr for ScContractCode { let dv: ScContractCodeType = ::read_xdr(r)?; #[allow(clippy::match_same_arms, clippy::match_wildcard_for_single_variants)] let v = match dv { - ScContractCodeType::Wasm => Self::Wasm(VecM::::read_xdr(r)?), + ScContractCodeType::Wasm => Self::Wasm(BytesM::<256000>::read_xdr(r)?), ScContractCodeType::Token => Self::Token, #[allow(unreachable_patterns)] _ => return Err(Error::Invalid), @@ -32572,7 +33490,7 @@ pub enum ScObject { Map(ScMap), U64(u64), I64(i64), - Bytes(VecM), + Bytes(BytesM<256000>), BigInt(ScBigInt), ContractCode(ScContractCode), AccountId(AccountId), @@ -32667,7 +33585,7 @@ impl ReadXdr for ScObject { ScObjectType::Map => Self::Map(ScMap::read_xdr(r)?), ScObjectType::U64 => Self::U64(u64::read_xdr(r)?), ScObjectType::I64 => Self::I64(i64::read_xdr(r)?), - ScObjectType::Bytes => Self::Bytes(VecM::::read_xdr(r)?), + ScObjectType::Bytes => Self::Bytes(BytesM::<256000>::read_xdr(r)?), ScObjectType::BigInt => Self::BigInt(ScBigInt::read_xdr(r)?), ScObjectType::ContractCode => Self::ContractCode(ScContractCode::read_xdr(r)?), ScObjectType::AccountId => Self::AccountId(AccountId::read_xdr(r)?), @@ -33381,14 +34299,14 @@ impl WriteXdr for ScSpecTypeBytesN { serde(rename_all = "camelCase") )] pub struct ScSpecTypeUdt { - pub name: VecM, + pub name: StringM<60>, } impl ReadXdr for ScSpecTypeUdt { #[cfg(feature = "std")] fn read_xdr(r: &mut impl Read) -> Result { Ok(Self { - name: VecM::::read_xdr(r)?, + name: StringM::<60>::read_xdr(r)?, }) } } @@ -33683,7 +34601,7 @@ impl WriteXdr for ScSpecTypeDef { serde(rename_all = "camelCase") )] pub struct ScSpecUdtStructFieldV0 { - pub name: VecM, + pub name: StringM<30>, pub type_: ScSpecTypeDef, } @@ -33691,7 +34609,7 @@ impl ReadXdr for ScSpecUdtStructFieldV0 { #[cfg(feature = "std")] fn read_xdr(r: &mut impl Read) -> Result { Ok(Self { - name: VecM::::read_xdr(r)?, + name: StringM::<30>::read_xdr(r)?, type_: ScSpecTypeDef::read_xdr(r)?, }) } @@ -33723,8 +34641,8 @@ impl WriteXdr for ScSpecUdtStructFieldV0 { serde(rename_all = "camelCase") )] pub struct ScSpecUdtStructV0 { - pub lib: VecM, - pub name: VecM, + pub lib: StringM<80>, + pub name: StringM<60>, pub fields: VecM, } @@ -33732,8 +34650,8 @@ impl ReadXdr for ScSpecUdtStructV0 { #[cfg(feature = "std")] fn read_xdr(r: &mut impl Read) -> Result { Ok(Self { - lib: VecM::::read_xdr(r)?, - name: VecM::::read_xdr(r)?, + lib: StringM::<80>::read_xdr(r)?, + name: StringM::<60>::read_xdr(r)?, fields: VecM::::read_xdr(r)?, }) } @@ -33765,7 +34683,7 @@ impl WriteXdr for ScSpecUdtStructV0 { serde(rename_all = "camelCase") )] pub struct ScSpecUdtUnionCaseV0 { - pub name: VecM, + pub name: StringM<60>, pub type_: Option, } @@ -33773,7 +34691,7 @@ impl ReadXdr for ScSpecUdtUnionCaseV0 { #[cfg(feature = "std")] fn read_xdr(r: &mut impl Read) -> Result { Ok(Self { - name: VecM::::read_xdr(r)?, + name: StringM::<60>::read_xdr(r)?, type_: Option::::read_xdr(r)?, }) } @@ -33805,8 +34723,8 @@ impl WriteXdr for ScSpecUdtUnionCaseV0 { serde(rename_all = "camelCase") )] pub struct ScSpecUdtUnionV0 { - pub lib: VecM, - pub name: VecM, + pub lib: StringM<80>, + pub name: StringM<60>, pub cases: VecM, } @@ -33814,8 +34732,8 @@ impl ReadXdr for ScSpecUdtUnionV0 { #[cfg(feature = "std")] fn read_xdr(r: &mut impl Read) -> Result { Ok(Self { - lib: VecM::::read_xdr(r)?, - name: VecM::::read_xdr(r)?, + lib: StringM::<80>::read_xdr(r)?, + name: StringM::<60>::read_xdr(r)?, cases: VecM::::read_xdr(r)?, }) } @@ -33847,7 +34765,7 @@ impl WriteXdr for ScSpecUdtUnionV0 { serde(rename_all = "camelCase") )] pub struct ScSpecUdtEnumCaseV0 { - pub name: VecM, + pub name: StringM<60>, pub value: u32, } @@ -33855,7 +34773,7 @@ impl ReadXdr for ScSpecUdtEnumCaseV0 { #[cfg(feature = "std")] fn read_xdr(r: &mut impl Read) -> Result { Ok(Self { - name: VecM::::read_xdr(r)?, + name: StringM::<60>::read_xdr(r)?, value: u32::read_xdr(r)?, }) } @@ -33887,8 +34805,8 @@ impl WriteXdr for ScSpecUdtEnumCaseV0 { serde(rename_all = "camelCase") )] pub struct ScSpecUdtEnumV0 { - pub lib: VecM, - pub name: VecM, + pub lib: StringM<80>, + pub name: StringM<60>, pub cases: VecM, } @@ -33896,8 +34814,8 @@ impl ReadXdr for ScSpecUdtEnumV0 { #[cfg(feature = "std")] fn read_xdr(r: &mut impl Read) -> Result { Ok(Self { - lib: VecM::::read_xdr(r)?, - name: VecM::::read_xdr(r)?, + lib: StringM::<80>::read_xdr(r)?, + name: StringM::<60>::read_xdr(r)?, cases: VecM::::read_xdr(r)?, }) } @@ -33929,7 +34847,7 @@ impl WriteXdr for ScSpecUdtEnumV0 { serde(rename_all = "camelCase") )] pub struct ScSpecUdtErrorEnumCaseV0 { - pub name: VecM, + pub name: StringM<60>, pub value: u32, } @@ -33937,7 +34855,7 @@ impl ReadXdr for ScSpecUdtErrorEnumCaseV0 { #[cfg(feature = "std")] fn read_xdr(r: &mut impl Read) -> Result { Ok(Self { - name: VecM::::read_xdr(r)?, + name: StringM::<60>::read_xdr(r)?, value: u32::read_xdr(r)?, }) } @@ -33969,8 +34887,8 @@ impl WriteXdr for ScSpecUdtErrorEnumCaseV0 { serde(rename_all = "camelCase") )] pub struct ScSpecUdtErrorEnumV0 { - pub lib: VecM, - pub name: VecM, + pub lib: StringM<80>, + pub name: StringM<60>, pub cases: VecM, } @@ -33978,8 +34896,8 @@ impl ReadXdr for ScSpecUdtErrorEnumV0 { #[cfg(feature = "std")] fn read_xdr(r: &mut impl Read) -> Result { Ok(Self { - lib: VecM::::read_xdr(r)?, - name: VecM::::read_xdr(r)?, + lib: StringM::<80>::read_xdr(r)?, + name: StringM::<60>::read_xdr(r)?, cases: VecM::::read_xdr(r)?, }) } @@ -34011,7 +34929,7 @@ impl WriteXdr for ScSpecUdtErrorEnumV0 { serde(rename_all = "camelCase") )] pub struct ScSpecFunctionInputV0 { - pub name: VecM, + pub name: StringM<30>, pub type_: ScSpecTypeDef, } @@ -34019,7 +34937,7 @@ impl ReadXdr for ScSpecFunctionInputV0 { #[cfg(feature = "std")] fn read_xdr(r: &mut impl Read) -> Result { Ok(Self { - name: VecM::::read_xdr(r)?, + name: StringM::<30>::read_xdr(r)?, type_: ScSpecTypeDef::read_xdr(r)?, }) } @@ -34051,7 +34969,7 @@ impl WriteXdr for ScSpecFunctionInputV0 { serde(rename_all = "camelCase") )] pub struct ScSpecFunctionV0 { - pub name: VecM, + pub name: StringM<10>, pub inputs: VecM, pub outputs: VecM, } @@ -34060,7 +34978,7 @@ impl ReadXdr for ScSpecFunctionV0 { #[cfg(feature = "std")] fn read_xdr(r: &mut impl Read) -> Result { Ok(Self { - name: VecM::::read_xdr(r)?, + name: StringM::<10>::read_xdr(r)?, inputs: VecM::::read_xdr(r)?, outputs: VecM::::read_xdr(r)?, }) diff --git a/tests/tx_debug_display.rs b/tests/tx_debug_display.rs new file mode 100644 index 00000000..208caff6 --- /dev/null +++ b/tests/tx_debug_display.rs @@ -0,0 +1,110 @@ +use stellar_xdr::{BytesM, Error, Hash, StringM, VecM}; + +#[test] +fn test_debug() { + // Renders as array. + assert_eq!( + format!( + "{:?}", + <_ as TryInto>>::try_into("hello world").unwrap() + ), + "VecM([104, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100])" + ); + // Renders as hex. + assert_eq!( + format!( + "{:?}", + <_ as TryInto>::try_into("hello world").unwrap() + ), + "BytesM(68656c6c6f20776f726c64)" + ); + // Renders as string. + assert_eq!( + format!( + "{:?}", + <_ as TryInto>::try_into("hello world").unwrap() + ), + "StringM(hello world)" + ); + // Renders as hex. + assert_eq!( + format!( + "{:?}", + <_ as TryInto>::try_into(*b"01234567890123456789013456789012").unwrap() + ), + "Hash(3031323334353637383930313233343536373839303133343536373839303132)" + ); +} + +#[test] +fn test_debug_invalid_utf8() -> Result<(), Error> { + // VecM is unchanged. + assert_eq!( + format!( + "{:?}", + <_ as TryInto>>::try_into(b"hello\xc3\x28world")? + ), + "VecM([104, 101, 108, 108, 111, 195, 40, 119, 111, 114, 108, 100])" + ); + // BytesM is unchanged. + assert_eq!( + format!( + "{:?}", + <_ as TryInto>::try_into(b"hello\xc3\x28world")? + ), + "BytesM(68656c6c6fc328776f726c64)" + ); + // StringM replaces the invalid sequence with the Unicode replacement character. + assert_eq!( + format!( + "{:?}", + <_ as TryInto>::try_into(b"hello\xc3\x28world")? + ), + "StringM(hello�(world)" + ); + Ok(()) +} + +#[test] +fn test_display() -> Result<(), Error> { + // Renders as hex. + assert_eq!( + format!("{}", <_ as TryInto>::try_into("hello world")?), + "68656c6c6f20776f726c64" + ); + // Renders as string. + assert_eq!( + format!("{}", <_ as TryInto>::try_into("hello world")?), + "hello world" + ); + // Renders as hex. + assert_eq!( + format!( + "{}", + <_ as TryInto>::try_into(*b"01234567890123456789013456789012").unwrap() + ), + "3031323334353637383930313233343536373839303133343536373839303132" + ); + Ok(()) +} + +#[test] +fn test_display_invalid_utf8() -> Result<(), Error> { + // BytesM is unchanged. + assert_eq!( + format!( + "{}", + <_ as TryInto>::try_into(b"hello\xc3\x28world")? + ), + "68656c6c6fc328776f726c64" + ); + // StringM replaces the invalid sequence with the Unicode replacement character. + assert_eq!( + format!( + "{}", + <_ as TryInto>::try_into(b"hello\xc3\x28world")? + ), + "hello�(world" + ); + Ok(()) +} diff --git a/tests/tx_serde.rs b/tests/tx_serde.rs new file mode 100644 index 00000000..73811a2c --- /dev/null +++ b/tests/tx_serde.rs @@ -0,0 +1,49 @@ +#![cfg(all(feature = "std", feature = "serde"))] + +use stellar_xdr::{BytesM, Hash, StringM, VecM}; + +#[test] +fn test_serde_ser() -> Result<(), Box> { + assert_eq!( + serde_json::to_string(&<_ as TryInto>>::try_into("hello world")?)?, + "[104,101,108,108,111,32,119,111,114,108,100]" + ); + assert_eq!( + serde_json::to_string(&<_ as TryInto>::try_into("hello world")?)?, + "\"68656c6c6f20776f726c64\"" + ); + assert_eq!( + serde_json::to_string(&<_ as TryInto>::try_into("hello world")?)?, + "\"hello world\"" + ); + assert_eq!( + serde_json::to_string(&<_ as TryInto>::try_into( + *b"01234567890123456789013456789012" + )?)?, + "\"3031323334353637383930313233343536373839303133343536373839303132\"" + ); + + Ok(()) +} + +#[test] +fn test_serde_der() -> Result<(), Box> { + let v: VecM = serde_json::from_str("[104,101,108,108,111,32,119,111,114,108,100]")?; + assert_eq!(v, <_ as TryInto>>::try_into("hello world")?); + + let v: BytesM = serde_json::from_str("\"68656c6c6f20776f726c64\"")?; + assert_eq!(v, <_ as TryInto>::try_into("hello world")?); + + let v: StringM = serde_json::from_str("\"hello world\"")?; + assert_eq!(v, <_ as TryInto>::try_into("hello world")?,); + + let v: Hash = serde_json::from_str( + "\"3031323334353637383930313233343536373839303133343536373839303132\"", + )?; + assert_eq!( + v, + <_ as TryInto>::try_into(*b"01234567890123456789013456789012")?, + ); + + Ok(()) +}