Skip to content

Commit

Permalink
Build serde without default features (no_std)
Browse files Browse the repository at this point in the history
Our `alloc`-based compilation is based on a lack of the `"std"` feature,
but `serde` wants an explicit `"alloc"` feature enabled for `Vec`.
Instead, we can use it completely `no_std` by manually handling the
sequence of data.

Our `serde_test`-based testing is moved to a CI crate, so that doesn't
"infect" the features of the main crate.
  • Loading branch information
cuviper committed Jan 14, 2020
1 parent c76d0d3 commit c1bd573
Show file tree
Hide file tree
Showing 6 changed files with 46 additions and 27 deletions.
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ matrix:
before_script:
- rustup target add $TARGET
script:
- cargo build --verbose --target $TARGET --no-default-features --features i128
- cargo build --verbose --target $TARGET --no-default-features --features "i128 serde"
- name: "rustfmt"
rust: 1.31.0
before_script:
Expand Down
4 changes: 0 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@ features = ["std"]
optional = true
version = "1.0"
default-features = false
features = ["std"]

[dependencies.quickcheck]
optional = true
Expand All @@ -64,9 +63,6 @@ optional = true
version = "0.8"
default-features = false

[dev-dependencies.serde_test]
version = "1.0"

[features]
default = ["std"]
i128 = ["num-integer/i128", "num-traits/i128"]
Expand Down
12 changes: 12 additions & 0 deletions ci/big_serde/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[package]
name = "big_serde"
version = "0.1.0"
authors = ["Josh Stone <cuviper@gmail.com>"]

[dependencies]
num-traits = "0.2.11"
serde_test = "1.0"

[dependencies.num-bigint]
features = ["serde"]
path = "../.."
6 changes: 5 additions & 1 deletion tests/serde.rs → ci/big_serde/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,12 @@
//! The serialized formats should not change, even if we change our
//! internal representation, because we want to preserve forward and
//! backward compatibility of serialized data!
//!
//! This test is in a completely separate crate so its `serde_test`
//! dependency does not "infect" the rest of the build with `serde`'s
//! default features, especially not `serde/std`.
#![cfg(feature = "serde")]
#![cfg(test)]

extern crate num_bigint;
extern crate num_traits;
Expand Down
6 changes: 5 additions & 1 deletion ci/test_full.sh
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ esac

case "$TRAVIS_RUST_VERSION" in
1.1[5-9].* | 1.2[0-9].* | 1.3[0-5].*) ;;
*) NO_STD_FEATURES="i128" ;;
*) NO_STD_FEATURES="i128 serde" ;;
esac

# num-bigint should build and test everywhere.
Expand Down Expand Up @@ -54,3 +54,7 @@ fi
if [[ "$TRAVIS_RUST_VERSION" == "nightly" ]]; then
cargo bench --all-features --no-run
fi

case "$STD_FEATURES" in
*serde*) cargo test --manifest-path ci/big_serde/Cargo.toml
esac
43 changes: 23 additions & 20 deletions src/biguint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2678,23 +2678,20 @@ fn u32_from_u128(n: u128) -> (u32, u32, u32, u32) {
}

#[cfg(feature = "serde")]
#[cfg(not(u64_digit))]
impl serde::Serialize for BigUint {
#[cfg(not(u64_digit))]
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
// Note: do not change the serialization format, or it may break forward
// and backward compatibility of serialized data! If we ever change the
// internal representation, we should still serialize in base-`u32`.
let data: &Vec<u32> = &self.data;
let data: &[u32] = &self.data;
data.serialize(serializer)
}
}

#[cfg(feature = "serde")]
#[cfg(u64_digit)]
impl serde::Serialize for BigUint {
#[cfg(u64_digit)]
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
Expand Down Expand Up @@ -2722,19 +2719,6 @@ impl serde::Serialize for BigUint {
}

#[cfg(feature = "serde")]
#[cfg(not(u64_digit))]
impl<'de> serde::Deserialize<'de> for BigUint {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let data: Vec<u32> = Vec::deserialize(deserializer)?;
Ok(biguint_from_vec(data))
}
}

#[cfg(feature = "serde")]
#[cfg(u64_digit)]
impl<'de> serde::Deserialize<'de> for BigUint {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
Expand All @@ -2751,6 +2735,22 @@ impl<'de> serde::Deserialize<'de> for BigUint {
formatter.write_str("a sequence of unsigned 32-bit numbers")
}

#[cfg(not(u64_digit))]
fn visit_seq<S>(self, mut seq: S) -> Result<Self::Value, S::Error>
where
S: SeqAccess<'de>,
{
let len = seq.size_hint().unwrap_or(0);
let mut data = Vec::with_capacity(len);

while let Some(value) = seq.next_element::<u32>()? {
data.push(value);
}

Ok(biguint_from_vec(data))
}

#[cfg(u64_digit)]
fn visit_seq<S>(self, mut seq: S) -> Result<Self::Value, S::Error>
where
S: SeqAccess<'de>,
Expand All @@ -2763,8 +2763,11 @@ impl<'de> serde::Deserialize<'de> for BigUint {
let mut value = BigDigit::from(lo);
if let Some(hi) = seq.next_element::<u32>()? {
value |= BigDigit::from(hi) << 32;
data.push(value);
} else {
data.push(value);
break;
}
data.push(value);
}

Ok(biguint_from_vec(data))
Expand Down

0 comments on commit c1bd573

Please sign in to comment.