Skip to content
This repository has been archived by the owner on Aug 15, 2021. It is now read-only.

Commit

Permalink
Implement 'to_vec' and 'from_slice' for no_std
Browse files Browse the repository at this point in the history
We implement `to_vec()` and `from_slice()` in a `no_std` environment to
simplify serialization. For this we require the `alloc` feature flag.
  • Loading branch information
Thomas Scholtes authored and pyfisch committed Sep 8, 2019
1 parent d27e97d commit d769647
Show file tree
Hide file tree
Showing 7 changed files with 62 additions and 22 deletions.
5 changes: 3 additions & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,11 @@ before_script:
- rustup target add thumbv7em-none-eabihf # Any target that does not have a standard library will do
script:
- cargo fmt --all -- --check
- (rustup component add clippy && cargo clippy --all --all-features -- -D clippy::all) || true
- (rustup component add clippy && cargo clippy --all -- -D clippy::all) || true
- cargo build
- cargo test
- cargo build --no-default-features --target thumbv7em-none-eabihf # Test we can build a platform that does not have std.
- cargo build --no-default-features --features alloc --target thumbv7em-none-eabihf # Test we can build a platform that does not have std.
- cargo test --no-default-features --lib --tests # Run no_std tests
- [[ $TRAVIS_RUST_VERSION != "1.31.0" ]] && cargo build --no-default-features --features alloc
- cargo build --features unsealed_read_write # The crate should still build when the unsealed_read_write feature is enabled.
- cargo build --no-default-features --features unsealed_read_write # The crate should still build when the unsealed_read_write feature is enabled and std disabled.
3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,8 @@ serde_derive = { version = "1.0.14", default-features = false }

[features]
default = ["std"]
# Uses `alloc` library and adds support for vector functions with
# `no_std`.
alloc = ["serde/alloc"]
std = ["serde/std" ]
unsealed_read_write = []
11 changes: 6 additions & 5 deletions src/de.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,12 @@ use crate::error::{Error, ErrorCode, Result};
use crate::read::EitherLifetime;
#[cfg(feature = "unsealed_read_write")]
pub use crate::read::EitherLifetime;
use crate::read::Offset;
#[cfg(feature = "std")]
pub use crate::read::{IoRead, SliceRead};
pub use crate::read::IoRead;
use crate::read::Offset;
#[cfg(any(feature = "std", feature = "alloc"))]
pub use crate::read::SliceRead;
pub use crate::read::{MutSliceRead, Read, SliceReadFixed};

/// Decodes a value from CBOR data in a slice.
///
/// # Examples
Expand All @@ -41,7 +42,7 @@ pub use crate::read::{MutSliceRead, Read, SliceReadFixed};
/// let value: &str = de::from_slice(&v[..]).unwrap();
/// assert_eq!(value, "foobar");
/// ```
#[cfg(feature = "std")]
#[cfg(any(feature = "std", feature = "alloc"))]
pub fn from_slice<'a, T>(slice: &'a [u8]) -> Result<T>
where
T: de::Deserialize<'a>,
Expand Down Expand Up @@ -144,7 +145,7 @@ where
}
}

#[cfg(feature = "std")]
#[cfg(any(feature = "std", feature = "alloc"))]
impl<'a> Deserializer<SliceRead<'a>> {
/// Constructs a `Deserializer` which reads from a slice.
///
Expand Down
28 changes: 25 additions & 3 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -142,13 +142,19 @@
//! serde_cbor = { version = "0.10", default-features = false }
//! ```
//!
//! Without the `std` feature the functions [from_reader], [from_slice], [to_vec], and [to_writer]
//! are not exported. To export [from_slice] and [to_vec] enable the `alloc` feature. The `alloc`
//! feature uses the [`alloc` library][alloc-lib] and requires at least version 1.36.0 of Rust.
//!
//! [alloc-lib]: https://doc.rust-lang.org/alloc/
//!
//! *Note*: to use derive macros in serde you will need to declare `serde`
//! dependency like so:
//! ``` toml
//! serde = { version = "1.0", default-features = false, features = ["derive"] }
//! ```
//!
//! Serialize an object.
//! Serialize an object with `no_std` and without `alloc`.
//! ``` rust
//! # #[macro_use] extern crate serde_derive;
//! # fn main() -> Result<(), serde_cbor::Error> {
Expand Down Expand Up @@ -258,6 +264,9 @@
#[cfg(all(not(feature = "std"), test))]
extern crate std;

#[cfg(feature = "alloc")]
extern crate alloc;

pub mod de;
pub mod error;
mod read;
Expand All @@ -270,18 +279,31 @@ pub mod value;
// Re-export the [items recommended by serde](https://serde.rs/conventions.html).
#[doc(inline)]
pub use crate::de::{Deserializer, StreamDeserializer};

#[doc(inline)]
pub use crate::error::{Error, Result};

#[doc(inline)]
pub use crate::ser::Serializer;

// Convenience functions for serialization and deserialization.
// These functions are only available in `std` mode.
#[cfg(feature = "std")]
#[doc(inline)]
pub use crate::de::{from_reader, from_slice};
pub use crate::de::from_reader;

#[cfg(any(feature = "std", feature = "alloc"))]
#[doc(inline)]
pub use crate::de::from_slice;

#[cfg(any(feature = "std", feature = "alloc"))]
#[doc(inline)]
pub use crate::ser::to_vec;

#[cfg(feature = "std")]
#[doc(inline)]
pub use crate::ser::{to_vec, to_writer};
pub use crate::ser::to_writer;

// Re-export the value type like serde_json
#[cfg(feature = "std")]
#[doc(inline)]
Expand Down
15 changes: 10 additions & 5 deletions src/read.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#[cfg(feature = "alloc")]
use alloc::{vec, vec::Vec};
#[cfg(feature = "std")]
use core::cmp;
use core::mem;
Expand Down Expand Up @@ -284,15 +286,15 @@ where
}

/// A CBOR input source that reads from a slice of bytes.
#[cfg(feature = "std")]
#[cfg(any(feature = "std", feature = "alloc"))]
#[derive(Debug)]
pub struct SliceRead<'a> {
slice: &'a [u8],
scratch: Vec<u8>,
index: usize,
}

#[cfg(feature = "std")]
#[cfg(any(feature = "std", feature = "alloc"))]
impl<'a> SliceRead<'a> {
/// Creates a CBOR input source to read from a slice of bytes.
pub fn new(slice: &'a [u8]) -> SliceRead<'a> {
Expand All @@ -314,18 +316,21 @@ impl<'a> SliceRead<'a> {
}
}

#[cfg(feature = "std")]
#[cfg(any(feature = "std", feature = "alloc"))]
impl<'a> Offset for SliceRead<'a> {
#[inline]
fn byte_offset(&self) -> usize {
self.index
}
}

#[cfg(all(feature = "std", not(feature = "unsealed_read_write")))]
#[cfg(all(
any(feature = "std", feature = "alloc"),
not(feature = "unsealed_read_write")
))]
impl<'a> private::Sealed for SliceRead<'a> {}

#[cfg(feature = "std")]
#[cfg(any(feature = "std", feature = "alloc"))]
impl<'a> Read<'a> for SliceRead<'a> {
#[inline]
fn next(&mut self) -> Result<Option<u8>> {
Expand Down
7 changes: 5 additions & 2 deletions src/ser.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
//! Serialize a Rust data structure to CBOR data.

#[cfg(feature = "alloc")]
use alloc::vec::Vec;

#[cfg(feature = "std")]
pub use crate::write::IoWrite;
pub use crate::write::{SliceWrite, Write};
Expand All @@ -12,13 +15,13 @@ use serde::ser::{self, Serialize};
use std::io;

/// Serializes a value to a vector.
#[cfg(feature = "std")]
#[cfg(any(feature = "std", feature = "alloc"))]
pub fn to_vec<T>(value: &T) -> Result<Vec<u8>>
where
T: ser::Serialize,
{
let mut vec = Vec::new();
to_writer(&mut vec, value)?;
value.serialize(&mut Serializer::new(&mut vec))?;
Ok(vec)
}

Expand Down
15 changes: 10 additions & 5 deletions src/write.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#[cfg(feature = "alloc")]
use alloc::vec::Vec;
#[cfg(not(feature = "std"))]
use core::fmt;
#[cfg(feature = "std")]
Expand Down Expand Up @@ -90,17 +92,20 @@ impl<W: io::Write> Write for IoWrite<W> {
#[cfg(all(feature = "std", not(feature = "unsealed_read_write")))]
impl<W> private::Sealed for IoWrite<W> where W: io::Write {}

// TODO this should be possible with just alloc
#[cfg(feature = "std")]
#[cfg(any(feature = "std", feature = "alloc"))]
impl Write for Vec<u8> {
type Error = io::Error;
type Error = error::Error;

fn write_all(&mut self, buf: &[u8]) -> Result<(), Self::Error> {
io::Write::write_all(self, buf)
self.extend_from_slice(buf);
Ok(())
}
}

#[cfg(all(feature = "std", not(feature = "unsealed_read_write")))]
#[cfg(all(
any(feature = "std", feature = "alloc"),
not(feature = "unsealed_read_write")
))]
impl private::Sealed for Vec<u8> {}

#[cfg(not(feature = "std"))]
Expand Down

0 comments on commit d769647

Please sign in to comment.