-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add value type, with serde and scale impls
- Loading branch information
Showing
12 changed files
with
4,653 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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, | ||
} |
Oops, something went wrong.