diff --git a/Cargo.toml b/Cargo.toml index a4eb2cc..0b5feb2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "bendy" -version = "0.2.0" +version = "0.2.1" edition = "2018" authors = [ @@ -10,7 +10,7 @@ authors = [ ] description = """ -A rust library for encoding and decoding bencode with enforced cannonicalization rules. +A rust library for encoding and decoding bencode with enforced canonicalization rules. """ repository = "https://github.com/P3KI/bendy" @@ -18,20 +18,39 @@ license = "BSD-3-Clause" readme = "README.md" keywords = ["bencode", "serialization", "deserialization", "bittorent"] -categories = ["encoding"] +categories = ["encoding", "decoding", "no-std"] [badges] maintenance = {status = "actively-developed"} +travis-ci = { repository = "P3KI/bendy" } [profile.release] lto = true +opt-level = 3 +codegen-units = 1 [dependencies] -failure = "^0.1.3" +failure = { version = "^0.1.3", default_features = false, features = ["derive"] } [dev-dependencies] regex = "^1.0" -skeptic = "^0.13" +doc-comment = "^0.3" -[build-dependencies] -skeptic = "^0.13" +### FEATURES ################################################################# + +[features] +default = ["std"] + +# Provide implementations for common standard library types like `Vec` and +# `HashMap`. Requires a dependency on the Rust standard library. +std = [ "failure/std" ] + +### Targets ################################################################## + +[[test]] +name = "core_test" +required-features = [ "std" ] + +[[example]] +name = "encode_torrent" +required-features = [ "std" ] diff --git a/README.md b/README.md index 52d8b12..11e171d 100644 --- a/README.md +++ b/README.md @@ -94,7 +94,10 @@ it is enough to import the trait and call the `to_bencode()` function on the obj ```rust use bendy::encoding::{ToBencode, Error}; -fn main() -> Result<(), Error> { +fn main() {} + +#[test] +fn encode_vector() -> Result<(), Error> { let my_data = vec!["hello", "world"]; let encoded = my_data.to_bencode()?; @@ -137,7 +140,10 @@ impl ToBencode for IntegerWrapper { } } -fn main() -> Result<(), Error> { +fn main() {} + +#[test] +fn encode_integer() -> Result<(), Error> { let example = IntegerWrapper(21); let encoded = example.to_bencode()?; @@ -168,7 +174,10 @@ impl ToBencode for StringWrapper { } } -fn main() -> Result<(), Error> { +fn main() {} + +#[test] +fn encode_string() -> Result<(), Error> { let example = StringWrapper("content".to_string()); let encoded = example.to_bencode()?; @@ -200,7 +209,10 @@ impl ToBencode for ByteStringWrapper { } } -fn main() -> Result<(), Error> { +fn main() {} + +#[test] +fn encode_byte_string() -> Result<(), Error> { let example = ByteStringWrapper(b"content".to_vec()); let encoded = example.to_bencode()?; @@ -246,7 +258,10 @@ impl ToBencode for Example { } } -fn main() -> Result<(), Error> { +fn main() {} + +#[test] +fn encode_dictionary() -> Result<(), Error> { let example = Example { label: "Example".to_string(), counter: 0 }; let encoded = example.to_bencode()?; @@ -278,7 +293,10 @@ impl ToBencode for Location { } } -fn main() -> Result<(), Error> { +fn main() {} + +#[test] +fn encode_list() -> Result<(), Error> { let example = Location(2, 3); let encoded = example.to_bencode()?; @@ -296,7 +314,10 @@ it is enough to import the trait and call the `from_bencode()` function on the o ```rust use bendy::decoding::{FromBencode, Error}; -fn main() -> Result<(), Error> { +fn main() {} + +#[test] +fn decode_vector() -> Result<(), Error> { let encoded = b"l5:hello5:worlde".to_vec(); let decoded = Vec::::from_bencode(&encoded)?; @@ -352,7 +373,10 @@ impl FromBencode for IntegerWrapper { } } -fn main() -> Result<(), Error> { +fn main() {} + +#[test] +fn decode_integer() -> Result<(), Error> { let encoded = b"i21e".to_vec(); let example = IntegerWrapper::from_bencode(&encoded)?; @@ -390,7 +414,10 @@ impl FromBencode for StringWrapper { } } -fn main() -> Result<(), Error> { +fn main() {} + +#[test] +fn decode_string() -> Result<(), Error> { let encoded = b"7:content".to_vec(); let example = StringWrapper::from_bencode(&encoded)?; @@ -425,7 +452,10 @@ impl FromBencode for ByteStringWrapper { } } -fn main() -> Result<(), Error> { +fn main() {} + +#[test] +fn decode_byte_string() -> Result<(), Error> { let encoded = b"7:content".to_vec(); let example = ByteStringWrapper::from_bencode(&encoded)?; @@ -492,7 +522,10 @@ impl FromBencode for Example { } } -fn main() -> Result<(), Error> { +fn main() {} + +#[test] +fn decode_dictionary() -> Result<(), Error> { let encoded = b"d7:counteri0e5:label7:Examplee".to_vec(); let expected = Example { label: "Example".to_string(), counter: 0 }; @@ -530,7 +563,9 @@ impl FromBencode for Location { } } -fn main() -> Result<(), Error> { +fn main() {} + +fn decode_list() -> Result<(), Error> { let encoded = b"li2ei3ee".to_vec(); let expected = Location(2, 3); diff --git a/build.rs b/build.rs deleted file mode 100644 index 64b479b..0000000 --- a/build.rs +++ /dev/null @@ -1,3 +0,0 @@ -fn main() { - skeptic::generate_doc_tests(&["README.md"]); -} diff --git a/rustfmt.toml b/rustfmt.toml index 6d380a8..0e6b31a 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -1,9 +1,9 @@ unstable_features = true -required_version = "1.0.3" +required_version = "1.3.0" edition = "2018" -format_doc_comments = true +format_code_in_doc_comments = true match_block_trailing_comma = true merge_imports = true reorder_impl_items = true diff --git a/src/decoding.rs b/src/decoding.rs index 413f5db..4928d87 100644 --- a/src/decoding.rs +++ b/src/decoding.rs @@ -4,10 +4,10 @@ //! For any decoding process, first we need to create a decoder: //! //! ``` -//! # use bendy::decoding::{Error, Decoder,Object}; +//! # use bendy::decoding::{Decoder}; //! # //! # let buf: &[u8] = b"d3:fooi1ee"; -//! let mut decoder = Decoder::new(buf); +//! let _decoder = Decoder::new(buf); //! ``` //! //! Decoders have a depth limit to prevent resource exhaustion from hostile inputs. By default, it's @@ -16,12 +16,11 @@ //! attacker can cause your program to use, so we recommend setting the bounds tightly: //! //! ``` -//! # use bendy::decoding::{Decoder,Object, Error}; +//! # use bendy::decoding::{Decoder}; //! # //! # let buf: &[u8] = b"d3:fooi1ee"; -//! # let mut decoder = Decoder::new(buf); -//! # -//! decoder = decoder.with_max_depth(3); +//! let _decoder = Decoder::new(buf) +//! .with_max_depth(3); //! ``` //! //! Atoms (integers and strings) have depth zero, and lists and dicts have a depth equal to the @@ -30,7 +29,7 @@ //! Now, you can start reading objects: //! //! ``` -//! # use bendy::decoding::{Decoder,Object, Error}; +//! # use bendy::decoding::{Decoder,Object}; //! # //! # fn decode_list(_: bendy::decoding::ListDecoder) {} //! # fn decode_dict(_: bendy::decoding::DictDecoder) {} @@ -42,8 +41,8 @@ //! None => (), // EOF //! Some(Object::List(d)) => decode_list(d), //! Some(Object::Dict(d)) => decode_dict(d), -//! Some(Object::Integer(s)) => (), // integer, as a string -//! Some(Object::Bytes(b)) => (), // A raw bytestring +//! Some(Object::Integer(_)) => (), // integer, as a string +//! Some(Object::Bytes(_)) => (), // A raw bytestring //! }; //! ``` //! @@ -61,7 +60,10 @@ //! decoder.next_object().ok(); // ignore the return value of this //! return decoder.next_object().is_ok(); //! } +//! # +//! # assert!(syntax_check(b"i18e")); //! ``` + mod decoder; mod error; mod from_bencode; diff --git a/src/decoding/decoder.rs b/src/decoding/decoder.rs index e80466c..7148236 100644 --- a/src/decoding/decoder.rs +++ b/src/decoding/decoder.rs @@ -1,3 +1,10 @@ +#[cfg(not(feature = "std"))] +use alloc::format; +#[cfg(not(feature = "std"))] +use core::str; +#[cfg(feature = "std")] +use std::{format, str}; + use crate::{ decoding::{Error, Object}, state_tracker::{StateTracker, StructureError, Token}, @@ -54,7 +61,6 @@ impl<'ser> Decoder<'ser> { } fn take_int(&mut self, expected_terminator: char) -> Result<&'ser str, StructureError> { - use std::str; enum State { Start, Sign, @@ -354,6 +360,13 @@ impl<'obj, 'ser: 'obj> Drop for ListDecoder<'obj, 'ser> { #[cfg(test)] mod test { + + #[cfg(not(feature = "std"))] + use alloc::{vec, vec::Vec}; + #[cfg(not(feature = "std"))] + use core::iter; + + #[cfg(feature = "std")] use std::iter; use regex; diff --git a/src/decoding/error.rs b/src/decoding/error.rs index c979727..111f641 100644 --- a/src/decoding/error.rs +++ b/src/decoding/error.rs @@ -1,4 +1,17 @@ +#[cfg(not(feature = "std"))] +use alloc::{ + format, + string::{FromUtf8Error, String, ToString}, +}; +#[cfg(not(feature = "std"))] +use core::{ + fmt::{self, Display, Formatter}, + num::ParseIntError, +}; + +#[cfg(feature = "std")] use std::{ + error::Error as StdError, fmt::{self, Display, Formatter}, sync::Arc, }; @@ -18,9 +31,14 @@ pub struct Error { /// An enumeration of potential errors that appear during bencode deserialization. #[derive(Debug, Clone, Fail)] pub enum ErrorKind { - /// Error that occurs if the serialized structure contains invalid information. + /// Error that occurs if the serialized structure contains invalid semantics. + #[cfg(feature = "std")] #[fail(display = "malformed content discovered: {}", _0)] MalformedContent(Arc), + /// Error that occurs if the serialized structure contains invalid semantics. + #[cfg(not(feature = "std"))] + #[fail(display = "malformed content discovered")] + MalformedContent, /// Error that occurs if the serialized structure is incomplete. #[fail(display = "missing field: {}", _0)] MissingField(String), @@ -36,7 +54,7 @@ pub enum ErrorKind { } pub trait ResultExt { - fn context(self, context: impl std::fmt::Display) -> Self; + fn context(self, context: impl Display) -> Self; } impl Error { @@ -52,6 +70,7 @@ impl Error { /// Raised when there is a general error while deserializing a type. /// The message should not be capitalized and should not end with a period. + #[cfg(feature = "std")] pub fn malformed_content(cause: impl Into) -> Error { let error = Arc::new(cause.into()); Self::from(ErrorKind::MalformedContent(error)) @@ -100,14 +119,29 @@ impl From for Error { } } -impl From for Error { +#[cfg(not(feature = "std"))] +impl From for Error { + fn from(_: FromUtf8Error) -> Self { + Self::from(ErrorKind::MalformedContent) + } +} + +#[cfg(not(feature = "std"))] +impl From for Error { + fn from(_: ParseIntError) -> Self { + Self::from(ErrorKind::MalformedContent) + } +} + +#[cfg(feature = "std")] +impl From for Error { fn from(error: T) -> Self { Self::malformed_content(error) } } impl ResultExt for Result { - fn context(self, context: impl std::fmt::Display) -> Result { + fn context(self, context: impl Display) -> Result { self.map_err(|err| err.context(context)) } } diff --git a/src/decoding/from_bencode.rs b/src/decoding/from_bencode.rs index a07bc7b..54e95c1 100644 --- a/src/decoding/from_bencode.rs +++ b/src/decoding/from_bencode.rs @@ -1,3 +1,7 @@ +#[cfg(not(feature = "std"))] +use alloc::{rc::Rc, string::String, vec::Vec}; + +#[cfg(feature = "std")] use std::{ collections::HashMap, hash::{BuildHasher, Hash}, @@ -88,6 +92,7 @@ impl FromBencode for String { } } +#[cfg(feature = "std")] impl FromBencode for HashMap where K: FromBencode + Hash + Eq, @@ -139,9 +144,13 @@ impl FromBencode for AsString> { #[cfg(test)] mod test { - use super::*; + #[cfg(not(feature = "std"))] + use alloc::{format, vec::Vec}; + use crate::encoding::AsString; + use super::*; + #[test] fn from_bencode_to_string_should_work_with_valid_input() { let expected_message = "hello"; diff --git a/src/decoding/object.rs b/src/decoding/object.rs index 70801ea..c2a43a9 100644 --- a/src/decoding/object.rs +++ b/src/decoding/object.rs @@ -100,7 +100,7 @@ impl<'obj, 'ser: 'obj> Object<'obj, 'ser> { /// # Examples /// /// ``` - /// use bendy::decoding::{Error, Object}; + /// use bendy::decoding::Object; /// /// let x = Object::Bytes(b"foo"); /// assert_eq!(b"foo", x.try_into_bytes().unwrap()); @@ -190,7 +190,7 @@ impl<'obj, 'ser: 'obj> Object<'obj, 'ser> { /// # Examples /// /// ``` - /// use bendy::decoding::{Error, Object}; + /// use bendy::decoding::Object; /// /// let x = Object::Integer("123"); /// assert_eq!("123", x.try_into_integer().unwrap()); @@ -282,7 +282,7 @@ impl<'obj, 'ser: 'obj> Object<'obj, 'ser> { /// # Examples /// /// ``` - /// use bendy::decoding::{Decoder, Error, Object}; + /// use bendy::decoding::{Decoder, Object}; /// /// let mut list_decoder = Decoder::new(b"le"); /// let x = list_decoder.next_object().unwrap().unwrap(); @@ -378,7 +378,7 @@ impl<'obj, 'ser: 'obj> Object<'obj, 'ser> { /// # Examples /// /// ``` - /// use bendy::decoding::{Decoder, Error, Object}; + /// use bendy::decoding::{Decoder, Object}; /// /// let mut dict_decoder = Decoder::new(b"de"); /// let x = dict_decoder.next_object().unwrap().unwrap(); diff --git a/src/encoding.rs b/src/encoding.rs index c286594..8113758 100644 --- a/src/encoding.rs +++ b/src/encoding.rs @@ -26,6 +26,15 @@ //! Ok(()) //! } //! } +//! # +//! # fn main() -> Result<(), Error> { +//! # let message = Message{ +//! # foo: 1, +//! # bar: "quux".to_string(), +//! # }; +//! # +//! # message.to_bencode().map(|_| ()) +//! # } //! ``` //! //! Then, messages can be serialized using [`ToBencode::to_bencode`]: @@ -53,13 +62,16 @@ //! # Ok(()) //! # } //! # } -//! # let result: Result, Error> = -//! Message{ -//! foo: 1, -//! bar: "quux".to_string(), -//! }.to_bencode() -//! # ; -//! # assert!(result.is_ok()); +//! # +//! # fn main() -> Result<(), Error> { +//! let message = Message{ +//! foo: 1, +//! bar: "quux".to_string(), +//! }; +//! +//! message.to_bencode() +//! # .map(|_| ()) +//! # } //! ``` //! //! Most primitive types already implement [`ToBencode`]. @@ -78,15 +90,16 @@ //! # use bendy::encoding::{ToBencode, Encoder, Error}; //! # //! # type ObjectType = u32; -//! # static object: u32 = 0; +//! # static OBJECT: u32 = 0; //! # //! # fn main() -> Result<(), Error> { -//! let mut encoder = Encoder::new() -//! .with_max_depth(ObjectType::MAX_DEPTH + 10); -//! encoder.emit(object)?; -//! encoder.get_output() -//! # .map_err(Error::from) -//! # .map(|_| ()) // ignore a success return value +//! let mut encoder = Encoder::new() +//! .with_max_depth(ObjectType::MAX_DEPTH + 10); +//! +//! encoder.emit(OBJECT)?; +//! encoder.get_output() +//! # .map_err(Error::from) +//! # .map(|_| ()) // ignore a success return value //! # } //! ``` //! diff --git a/src/encoding/encoder.rs b/src/encoding/encoder.rs index 21adfaf..b0544fa 100644 --- a/src/encoding/encoder.rs +++ b/src/encoding/encoder.rs @@ -1,4 +1,13 @@ -use std::{collections::BTreeMap, io::Write}; +#[cfg(not(feature = "std"))] +use alloc::{ + borrow::ToOwned, + collections::BTreeMap, + format, + string::{String, ToString}, + vec::Vec, +}; +#[cfg(feature = "std")] +use std::{collections::BTreeMap, vec::Vec}; use crate::{ encoding::{Error, PrintableInteger, ToBencode}, @@ -34,7 +43,9 @@ impl Encoder { Token::Dict => self.output.push(b'd'), Token::String(s) => { // Writing to a vec can't fail - write!(&mut self.output, "{}:", s.len()).unwrap(); + let length = s.len().to_string(); + self.output.extend_from_slice(length.as_bytes()); + self.output.push(b':'); self.output.extend_from_slice(s); }, Token::Num(num) => { @@ -89,7 +100,7 @@ impl Encoder { // possible (for performance) self.state.observe_token(&Token::Num(""))?; self.output.push(b'i'); - value.write_to(&mut self.output).unwrap(); // Vec can't produce an error + self.output.extend_from_slice(value.to_string().as_bytes()); self.output.push(b'e'); Ok(()) } @@ -114,13 +125,15 @@ impl Encoder { /// Example: /// /// ``` - /// # use bendy::encoding::Encoder; + /// # use bendy::encoding::{Encoder, Error}; /// # - /// # let mut encoder = Encoder::new(); - /// encoder.emit_dict(|mut e| { - /// e.emit_pair(b"a", "foo")?; - /// e.emit_pair(b"b", 2) - /// }); + /// # fn main() -> Result<(), Error>{ + /// let mut encoder = Encoder::new(); + /// encoder.emit_dict(|mut e| { + /// e.emit_pair(b"a", "foo")?; + /// e.emit_pair(b"b", 2) + /// }) + /// # } /// ``` pub fn emit_dict(&mut self, content_cb: F) -> Result<(), Error> where @@ -137,14 +150,15 @@ impl Encoder { /// E.g., to emit the list `[1,2,3]`, you would write /// /// ``` - /// # use bendy::encoding::Encoder; - /// # + /// # use bendy::encoding::{Encoder, Error}; + /// # fn main() -> Result<(), Error> { /// let mut encoder = Encoder::new(); /// encoder.emit_list(|e| { - /// e.emit_int(1)?; - /// e.emit_int(2)?; - /// e.emit_int(3) - /// }); + /// e.emit_int(1)?; + /// e.emit_int(2)?; + /// e.emit_int(3) + /// }) + /// # } /// ``` pub fn emit_list(&mut self, list_cb: F) -> Result<(), Error> where @@ -165,14 +179,12 @@ impl Encoder { /// # use bendy::encoding::{Encoder, Error}; /// # /// # fn main() -> Result<(), Error> { - /// # let mut encoder = Encoder::new(); - /// # - /// encoder.emit_and_sort_dict(|mut e| { - /// // Unlike in the example for Encoder::emit_dict(), these keys aren't sorted - /// e.emit_pair(b"b", 2)?; - /// e.emit_pair(b"a", "foo") - /// })?; - /// Ok(()) + /// let mut encoder = Encoder::new(); + /// encoder.emit_and_sort_dict(|e| { + /// // Unlike in the example for Encoder::emit_dict(), these keys aren't sorted + /// e.emit_pair(b"b", 2)?; + /// e.emit_pair(b"a", "foo") + /// }) /// # } /// ``` pub fn emit_and_sort_dict(&mut self, content_cb: F) -> Result<(), Error> @@ -345,7 +357,11 @@ impl UnsortedDictEncoder { where F: FnOnce(SingleItemEncoder) -> Result<(), Error>, { + #[cfg(not(feature = "std"))] + use alloc::collections::btree_map::Entry; + #[cfg(feature = "std")] use std::collections::btree_map::Entry; + if self.error.is_err() { return self.error.clone(); } diff --git a/src/encoding/error.rs b/src/encoding/error.rs index 7809486..f97a911 100644 --- a/src/encoding/error.rs +++ b/src/encoding/error.rs @@ -1,3 +1,4 @@ +#[cfg(feature = "std")] use std::sync::Arc; use failure::Fail; @@ -12,9 +13,13 @@ pub struct Error(#[fail(cause)] pub ErrorKind); #[derive(Debug, Clone, Fail)] pub enum ErrorKind { /// Error that occurs if the serialized structure contains invalid semantics. + #[cfg(feature = "std")] #[fail(display = "malformed content discovered: {}", _0)] MalformedContent(Arc), - + /// Error that occurs if the serialized structure contains invalid semantics. + #[cfg(not(feature = "std"))] + #[fail(display = "malformed content discovered")] + MalformedContent, /// Error in the bencode structure (e.g. a missing field end separator). #[fail(display = "bencode encoding corrupted")] StructureError(#[fail(cause)] StructureError), @@ -23,6 +28,7 @@ pub enum ErrorKind { impl Error { /// Raised when there is a general error while deserializing a type. /// The message should not be capitalized and should not end with a period. + #[cfg(feature = "std")] pub fn malformed_content(cause: impl Into) -> Error { let error = Arc::new(cause.into()); Self(ErrorKind::MalformedContent(error)) diff --git a/src/encoding/printable_integer.rs b/src/encoding/printable_integer.rs index cc09554..c795e80 100644 --- a/src/encoding/printable_integer.rs +++ b/src/encoding/printable_integer.rs @@ -1,18 +1,14 @@ -use std::io::{self, Write}; +#[cfg(not(feature = "std"))] +use core::fmt::Display; +#[cfg(feature = "std")] +use std::fmt::Display; /// A value that can be formatted as a decimal integer -pub trait PrintableInteger { - /// Write the value as a decimal integer - fn write_to(self, w: W) -> io::Result<()>; -} +pub trait PrintableInteger: Display {} macro_rules! impl_integer { ($($type:ty)*) => {$( - impl PrintableInteger for $type { - fn write_to(self, mut w: W) -> io::Result<()> { - write!(w, "{}", self) - } - } + impl PrintableInteger for $type {} )*} } diff --git a/src/encoding/to_bencode.rs b/src/encoding/to_bencode.rs index 7cb08b2..3630cfb 100644 --- a/src/encoding/to_bencode.rs +++ b/src/encoding/to_bencode.rs @@ -1,6 +1,18 @@ +#[cfg(not(feature = "std"))] +use alloc::{ + collections::{BTreeMap, LinkedList, VecDeque}, + rc::Rc, + string::String, + sync::Arc, + vec::Vec, +}; + +#[cfg(feature = "std")] use std::{ collections::{BTreeMap, HashMap, LinkedList, VecDeque}, - hash::Hash, + hash::{BuildHasher, Hash}, + rc::Rc, + sync::Arc, }; use crate::encoding::{Encoder, Error, SingleItemEncoder}; @@ -37,6 +49,7 @@ impl<'a, E: 'a + ToBencode + Sized> ToBencode for &'a E { } } +#[cfg(feature = "std")] impl ToBencode for Box { const MAX_DEPTH: usize = E::MAX_DEPTH; @@ -45,7 +58,7 @@ impl ToBencode for Box { } } -impl ToBencode for ::std::rc::Rc { +impl ToBencode for Rc { const MAX_DEPTH: usize = E::MAX_DEPTH; fn encode(&self, encoder: SingleItemEncoder) -> Result<(), Error> { @@ -53,7 +66,7 @@ impl ToBencode for ::std::rc::Rc { } } -impl ToBencode for ::std::sync::Arc { +impl ToBencode for Arc { const MAX_DEPTH: usize = E::MAX_DEPTH; fn encode(&self, encoder: SingleItemEncoder) -> Result<(), Error> { @@ -149,11 +162,12 @@ impl, V: ToBencode> ToBencode for BTreeMap { } } +#[cfg(feature = "std")] impl ToBencode for HashMap where K: AsRef<[u8]> + Eq + Hash, V: ToBencode, - S: ::std::hash::BuildHasher, + S: BuildHasher, { const MAX_DEPTH: usize = V::MAX_DEPTH + 1; @@ -207,6 +221,9 @@ where #[cfg(test)] mod test { + #[cfg(not(feature = "std"))] + use alloc::{borrow::ToOwned, vec}; + use super::*; struct Foo { diff --git a/src/lib.rs b/src/lib.rs index 458c05e..2bc4a3c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,6 +5,14 @@ //! //! The encoder is likewise designed to ensure that it only produces valid structures. +#![cfg_attr(not(feature = "std"), no_std)] + +#[cfg(not(feature = "std"))] +extern crate alloc; + pub mod decoding; pub mod encoding; pub mod state_tracker; + +#[cfg(test)] +doc_comment::doctest!("../README.md"); diff --git a/src/state_tracker/stack.rs b/src/state_tracker/stack.rs index 449d5f8..b61c03e 100644 --- a/src/state_tracker/stack.rs +++ b/src/state_tracker/stack.rs @@ -1,3 +1,6 @@ +#[cfg(not(feature = "std"))] +use alloc::vec::Vec; + pub trait Stack { fn peek_mut(&mut self) -> Option<&mut T>; diff --git a/src/state_tracker/state.rs b/src/state_tracker/state.rs index 8ed757a..783fa1a 100644 --- a/src/state_tracker/state.rs +++ b/src/state_tracker/state.rs @@ -1,3 +1,6 @@ +#[cfg(not(feature = "std"))] +use alloc::vec::Vec; + use crate::state_tracker::{Stack, StructureError, Token}; /// The state of current level of the decoder diff --git a/src/state_tracker/structure_error.rs b/src/state_tracker/structure_error.rs index 14818c7..64dae70 100644 --- a/src/state_tracker/structure_error.rs +++ b/src/state_tracker/structure_error.rs @@ -1,6 +1,15 @@ -use failure::Fail; +#[cfg(not(feature = "std"))] +use alloc::{ + format, + string::{String, ToString}, +}; +#[cfg(not(feature = "std"))] +use core::fmt::Display; +#[cfg(feature = "std")] use std::fmt::Display; +use failure::Fail; + /// An encoding or decoding error #[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Fail)] pub enum StructureError { diff --git a/tests/skeptic.rs b/tests/skeptic.rs deleted file mode 100644 index ff46c9c..0000000 --- a/tests/skeptic.rs +++ /dev/null @@ -1 +0,0 @@ -include!(concat!(env!("OUT_DIR"), "/skeptic-tests.rs"));