Skip to content

Commit

Permalink
Add value type, with serde and scale impls
Browse files Browse the repository at this point in the history
  • Loading branch information
jsdw committed May 18, 2022
1 parent 9f858de commit 0aea2ae
Show file tree
Hide file tree
Showing 12 changed files with 4,653 additions and 6 deletions.
91 changes: 85 additions & 6 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,87 @@
#[cfg(test)]
mod tests {
#[test]
fn it_works() {
let result = 2 + 2;
assert_eq!(result, 4);
// Copyright 2019-2022 Parity Technologies (UK) Ltd.
// This file is part of subxt.
//
// subxt is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// subxt is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with subxt. If not, see <http://www.gnu.org/licenses/>.

//! This crate exposes the [`Value`] type and related subtypes, which are used as the runtime
//! representations of SCALE encoded data (much like `serde_json::Value` is a runtime representation
//! of JSON data).

mod scale_impls;
#[cfg(feature = "serde")]
mod serde_impls;
mod value_type;

pub use value_type::{
BitSequence,
Composite,
Primitive,
Value,
ValueDef,
Variant,
};

/// Serializing and deserializing a [`crate::Value`] into/from other types via serde.
#[cfg(feature = "serde")]
pub mod serde {
pub use crate::serde_impls::DeserializeError;

/// Attempt to deserialize a [`crate::Value`] into another type.
pub fn from_value<'de, Ctx, T: serde::Deserialize<'de>>(
value: crate::Value<Ctx>,
) -> Result<T, DeserializeError> {
T::deserialize(value)
}

// TODO: Eventually let's implement Serializer on Value so that we can convert from some type into a Value:
//
// /// Attempt to serialize some type into a [`crate::Value`].
// pub fn to_value<'de, Ctx, T: serde::Serialize>(ty: T) -> Result<crate::Value<()>, SerializeError> {
// ty.serialize(serializer)
// }
}

/// Encoding and decoding SCALE bytes into a [`crate::Value`].
pub mod scale {
pub use crate::scale_impls::{
BitSequenceError,
DecodeError,
EncodeError,
TypeId,
};
pub use scale_info::PortableRegistry;

/// Attempt to decode some SCALE encoded bytes into a value, by providing a pointer
/// to the bytes (which will be moved forwards as bytes are used in the decoding),
/// a type ID, and a type registry from which we'll look up the relevant type information.
pub fn decode_as_type<Id: Into<TypeId>>(
data: &mut &[u8],
ty_id: Id,
types: &PortableRegistry,
) -> Result<crate::Value<TypeId>, DecodeError> {
crate::scale_impls::decode_value_as_type(data, ty_id, types)
}

/// Attempt to encode some [`Value<T>`] into SCALE bytes, by providing a pointer to the
/// type ID that we'd like to encode it as, a type registry from which we'll look
/// up the relevant type information, and a buffer to encode the bytes to.
pub fn encode_as_type<T, Id: Into<TypeId>>(
value: crate::Value<T>,
ty_id: Id,
types: &PortableRegistry,
buf: &mut Vec<u8>,
) -> Result<(), EncodeError<T>> {
crate::scale_impls::encode_value_as_type(value, ty_id, types, buf)
}
}
94 changes: 94 additions & 0 deletions src/scale_impls/bit_sequence.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
// Copyright 2019-2022 Parity Technologies (UK) Ltd.
// This file is part of subxt.
//
// subxt is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// subxt is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with subxt. If not, see <http://www.gnu.org/licenses/>.

use super::ScaleTypeDef as TypeDef;
use scale_info::{
form::PortableForm,
PortableRegistry,
TypeDefBitSequence,
TypeDefPrimitive,
};

#[derive(Debug, Clone, thiserror::Error, PartialEq)]
pub enum BitSequenceError {
#[error("Bit order type {0} not found in registry")]
BitOrderTypeNotFound(u32),
#[error("Bit store type {0} not found in registry")]
BitStoreTypeNotFound(u32),
#[error("Bit order cannot be identified")]
NoBitOrderIdent,
#[error("Bit store type {0} is not supported")]
StoreTypeNotSupported(String),
#[error("Bit order type {0} is not supported")]
OrderTypeNotSupported(String),
}

/// Obtain details about a bit sequence.
pub fn get_bitsequence_details(
ty: &TypeDefBitSequence<PortableForm>,
types: &PortableRegistry,
) -> Result<(BitOrderTy, BitStoreTy), BitSequenceError> {
let bit_store_ty = ty.bit_store_type().id();
let bit_order_ty = ty.bit_order_type().id();

// What is the backing store type expected?
let bit_store_def = types
.resolve(bit_store_ty)
.ok_or(BitSequenceError::BitStoreTypeNotFound(bit_store_ty))?
.type_def();

// What is the bit order type expected?
let bit_order_def = types
.resolve(bit_order_ty)
.ok_or(BitSequenceError::BitOrderTypeNotFound(bit_order_ty))?
.path()
.ident()
.ok_or(BitSequenceError::NoBitOrderIdent)?;

let bit_order_out = match bit_store_def {
TypeDef::Primitive(TypeDefPrimitive::U8) => Some(BitOrderTy::U8),
TypeDef::Primitive(TypeDefPrimitive::U16) => Some(BitOrderTy::U16),
TypeDef::Primitive(TypeDefPrimitive::U32) => Some(BitOrderTy::U32),
TypeDef::Primitive(TypeDefPrimitive::U64) => Some(BitOrderTy::U64),
_ => None,
}
.ok_or_else(|| {
BitSequenceError::OrderTypeNotSupported(format!("{bit_store_def:?}"))
})?;

let bit_store_out = match &*bit_order_def {
"Lsb0" => Some(BitStoreTy::Lsb0),
"Msb0" => Some(BitStoreTy::Msb0),
_ => None,
}
.ok_or(BitSequenceError::StoreTypeNotSupported(bit_order_def))?;

Ok((bit_order_out, bit_store_out))
}

#[derive(Copy, Clone, PartialEq)]
pub enum BitStoreTy {
Lsb0,
Msb0,
}

#[derive(Copy, Clone, PartialEq)]
pub enum BitOrderTy {
U8,
U16,
U32,
U64,
}

0 comments on commit 0aea2ae

Please sign in to comment.