Skip to main content

scale_serialization/
lib.rs

1#![cfg_attr(not(feature = "std"), no_std)]
2//!
3//! # Scales
4//!
5//! Dynamic SCALE Serialization using `scale-info` type information.
6
7#[cfg_attr(feature = "serializer", macro_use)]
8extern crate alloc;
9
10#[cfg(feature = "scale-info")]
11pub mod compress;
12pub mod error;
13pub mod registry;
14#[cfg(feature = "serializer")]
15mod serializer;
16#[cfg(feature = "text")]
17mod textfmt;
18mod value;
19
20pub use error::Error;
21pub use registry::{Registry, TypeDef, TypeId};
22#[cfg(feature = "json")]
23pub use serde_json::Value as JsonValue;
24#[cfg(feature = "serializer")]
25pub use serializer::{to_bytes, to_bytes_with_info, to_vec, to_vec_with_info, Serializer};
26#[cfg(all(feature = "serializer", feature = "json"))]
27pub use serializer::{to_bytes_from_iter, to_vec_from_iter};
28#[cfg(feature = "text")]
29pub use textfmt::{from_text, to_text};
30pub use value::{Cursor, FieldIter, SeqIter, TupleIter, Value};
31
32mod prelude {
33    pub use alloc::string::{String, ToString};
34    #[cfg(feature = "serializer")]
35    pub use alloc::vec::Vec;
36}
37
38// adapted from https://github.com/paritytech/parity-scale-codec/blob/master/src/compact.rs#L336
39#[cfg(any(feature = "serializer", feature = "text"))]
40#[allow(clippy::all)]
41pub(crate) fn compact_encode(n: u128, mut dest: impl bytes::BufMut) {
42    match n {
43        0..=0b0011_1111 => dest.put_u8((n as u8) << 2),
44        0..=0b0011_1111_1111_1111 => dest.put_u16_le(((n as u16) << 2) | 0b01),
45        0..=0b0011_1111_1111_1111_1111_1111_1111_1111 => dest.put_u32_le(((n as u32) << 2) | 0b10),
46        _ => {
47            let bytes_needed = 16 - n.leading_zeros() / 8;
48            debug_assert!(bytes_needed >= 4);
49            dest.put_u8(0b11 + ((bytes_needed - 4) << 2) as u8);
50            let mut v = n;
51            for _ in 0..bytes_needed {
52                dest.put_u8(v as u8);
53                v >>= 8;
54            }
55        }
56    }
57}
58
59/// Decode a hex string (without `0x` prefix) into bytes.
60#[cfg(any(feature = "serializer", feature = "text"))]
61pub(crate) fn decode_hex(hex: &str) -> Result<alloc::vec::Vec<u8>, Error> {
62    if !hex.len().is_multiple_of(2) {
63        return Err(Error::BadInput("odd number of hex digits".into()));
64    }
65    hex.as_bytes()
66        .chunks(2)
67        .map(|pair| {
68            let hi = hex_nibble(pair[0]).ok_or(Error::BadInput("invalid hex digit".into()))?;
69            let lo = hex_nibble(pair[1]).ok_or(Error::BadInput("invalid hex digit".into()))?;
70            Ok((hi << 4) | lo)
71        })
72        .collect()
73}
74
75#[cfg(any(feature = "serializer", feature = "text"))]
76#[inline]
77fn hex_nibble(b: u8) -> Option<u8> {
78    match b {
79        b'0'..=b'9' => Some(b - b'0'),
80        b'a'..=b'f' => Some(b - b'a' + 10),
81        b'A'..=b'F' => Some(b - b'A' + 10),
82        _ => None,
83    }
84}
85
86#[cfg(test)]
87mod tests;