Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add BitVec support #98

Merged
merged 6 commits into from
Jun 22, 2021
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ jobs:

- name: check-features
run: |
cargo check --no-default-features --features bit-vec
cargo check --no-default-features --features serde
cargo check --no-default-features --features serde,decode

Expand All @@ -50,7 +51,7 @@ jobs:

- name: test
run: |
cargo test --all
cargo test --all --all-features

- name: test no-std
run: |
Expand Down
6 changes: 6 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ categories = ["no-std", "encoding"]
include = ["Cargo.toml", "src/**/*.rs", "README.md", "LICENSE"]

[dependencies]
bitvec = { version = "0.20.1", default-features = false, features = ["alloc"], optional = true }
cfg-if = "1.0"
scale-info-derive = { version = "0.4.0", path = "derive", default-features = false, optional = true }
serde = { version = "1", default-features = false, optional = true, features = ["derive", "alloc"] }
Expand All @@ -23,6 +24,7 @@ scale = { package = "parity-scale-codec", version = "2.1", default-features = fa
[features]
default = ["std"]
std = [
"bitvec/std",
"scale/std",
]
derive = [
Expand All @@ -32,6 +34,10 @@ derive = [
decode = [
"scale/full"
]
# enables type information for bitvec types, matching the name of the parity-scale-codec feature
bit-vec = [
"bitvec"
]

[workspace]
members = [
Expand Down
35 changes: 35 additions & 0 deletions src/impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -286,3 +286,38 @@ where
TypeDefCompact::new(MetaType::new::<T>()).into()
}
}

#[cfg(feature = "bit-vec")]
impl<O, T> TypeInfo for bitvec::vec::BitVec<O, T>
where
O: bitvec::order::BitOrder + TypeInfo + 'static,
T: bitvec::store::BitStore + TypeInfo + 'static,
{
type Identity = Self;

fn type_info() -> Type {
crate::TypeDefBitVec::new::<O, T>().into()
}
}

#[cfg(feature = "bit-vec")]
impl TypeInfo for bitvec::order::Lsb0 {
type Identity = Self;

fn type_info() -> Type {
Type::builder()
.path(Path::new("Lsb0", "bitvec::order"))
.composite(Fields::unit())
}
}

#[cfg(feature = "bit-vec")]
impl TypeInfo for bitvec::order::Msb0 {
type Identity = Self;

fn type_info() -> Type {
Type::builder()
.path(Path::new("Msb0", "bitvec::order"))
.composite(Fields::unit())
}
}
27 changes: 27 additions & 0 deletions src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,33 @@ fn collections() {
);
}

#[cfg(feature = "bit-vec")]
#[test]
fn bitvec() {
use bitvec::{
order::{
Lsb0,
Msb0,
},
vec::BitVec,
};

assert_type!(
BitVec<Lsb0, u8>,
TypeDefBitVec::new::<Lsb0, u8>()
);

assert_type!(
BitVec<Msb0, u16>,
TypeDefBitVec::new::<Msb0, u16>()
);

assert_type!(
BitVec<Msb0, u32>,
TypeDefBitVec::new::<Msb0, u32>()
);
}

#[test]
fn scale_compact_types() {
assert_type!(Compact<i32>, TypeDefCompact::new(meta_type::<i32>()))
Expand Down
67 changes: 67 additions & 0 deletions src/ty/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,13 @@ impl_from_type_def_for_type!(
TypeDefPhantom,
);

#[cfg(feature = "bit-vec")]
impl From<crate::TypeDefBitVec> for Type {
fn from(item: crate::TypeDefBitVec) -> Self {
Self::new(Path::voldemort(), Vec::new(), item, Vec::new())
}
}

impl Type {
/// Create a [`TypeBuilder`](`crate::build::TypeBuilder`) the public API for constructing a [`Type`]
pub fn builder() -> TypeBuilder {
Expand Down Expand Up @@ -197,6 +204,9 @@ pub enum TypeDef<T: Form = MetaForm> {
Compact(TypeDefCompact<T>),
/// A PhantomData type.
Phantom(TypeDefPhantom<T>),
#[cfg(feature = "bit-vec")]
/// A BitVec type.
BitVec(TypeDefBitVec<T>),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think dtolnay mentioned that for compatibility with respect to different crate feature sets it is better to replace the inner type of BitVec with a placeholder type (dummy) of not(feature = "bit-vec") instead of entirely removing this variant.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is much better, will avoid issues with incompatible decoding if we add variants after this.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've removed the feature flag from this variant now so it will be binary compatible, and also so that decoding/deserializing is supported even without the feature enabled.

}

impl IntoPortable for TypeDef {
Expand All @@ -212,6 +222,8 @@ impl IntoPortable for TypeDef {
TypeDef::Primitive(primitive) => primitive.into(),
TypeDef::Compact(compact) => compact.into_portable(registry).into(),
TypeDef::Phantom(phantom) => phantom.into_portable(registry).into(),
#[cfg(feature = "bit-vec")]
TypeDef::BitVec(bitvec) => bitvec.into_portable(registry).into(),
}
}
}
Expand Down Expand Up @@ -485,3 +497,58 @@ where
&self.type_param
}
}

/// Type describing a [`bitvec::vec::BitVec`].
#[cfg(feature = "bit-vec")]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(any(feature = "std", feature = "decode"), derive(scale::Decode))]
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Encode, Debug)]
pub struct TypeDefBitVec<T: Form = MetaForm> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd rename this to TypeDefBitSequence to match with Sequence type definition.

/// The type implementing [`::bitvec::store::BitStore`].
bit_store_type: T::Type,
/// The type implementing [`::bitvec::order::BitOrder`].
bit_order_type: T::Type,
}

#[cfg(feature = "bit-vec")]
impl IntoPortable for crate::TypeDefBitVec {
type Output = crate::TypeDefBitVec<PortableForm>;

fn into_portable(self, registry: &mut Registry) -> Self::Output {
TypeDefBitVec {
bit_store_type: registry.register_type(&self.bit_store_type),
bit_order_type: registry.register_type(&self.bit_order_type),
}
}
}

#[cfg(feature = "bit-vec")]
impl TypeDefBitVec {
/// Creates a new phantom type definition.
ascjones marked this conversation as resolved.
Show resolved Hide resolved
pub fn new<O, T>() -> Self
where
O: bitvec::order::BitOrder + TypeInfo + 'static,
T: bitvec::store::BitStore + TypeInfo + 'static,
{
Self {
bit_order_type: MetaType::new::<O>(),
bit_store_type: MetaType::new::<T>(),
}
}
}

#[cfg(feature = "bit-vec")]
impl<T> TypeDefBitVec<T>
where
T: Form,
{
/// Returns the type of the bit ordering of the [`::bitvec::vec::BitVec`].
pub fn bit_order_type(&self) -> &T::Type {
&self.bit_order_type
}

/// Returns underlying type used to store the [`::bitvec::vec::BitVec`].
pub fn bit_store_type(&self) -> &T::Type {
&self.bit_store_type
}
}