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 no_std support and introduce feature std. #22

Merged
merged 3 commits into from
Jul 11, 2019
Merged
Show file tree
Hide file tree
Changes from all 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
33 changes: 26 additions & 7 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "bendy"
version = "0.2.0"
version = "0.2.1"
edition = "2018"

authors = [
Expand All @@ -10,28 +10,47 @@ 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"
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<T>` and
# `HashMap<K, V>`. 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" ]
59 changes: 47 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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()?;

Expand Down Expand Up @@ -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()?;
Expand Down Expand Up @@ -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()?;
Expand Down Expand Up @@ -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()?;
Expand Down Expand Up @@ -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()?;
Expand Down Expand Up @@ -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()?;
Expand All @@ -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::<String>::from_bencode(&encoded)?;

Expand Down Expand Up @@ -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)?;
Expand Down Expand Up @@ -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)?;
Expand Down Expand Up @@ -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)?;
Expand Down Expand Up @@ -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 };

Expand Down Expand Up @@ -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);

Expand Down
3 changes: 0 additions & 3 deletions build.rs

This file was deleted.

4 changes: 2 additions & 2 deletions rustfmt.toml
Original file line number Diff line number Diff line change
@@ -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
Expand Down
20 changes: 11 additions & 9 deletions src/decoding.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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) {}
Expand All @@ -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
//! };
//! ```
//!
Expand All @@ -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;
Expand Down
15 changes: 14 additions & 1 deletion src/decoding/decoder.rs
Original file line number Diff line number Diff line change
@@ -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},
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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;
Expand Down
42 changes: 38 additions & 4 deletions src/decoding/error.rs
Original file line number Diff line number Diff line change
@@ -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,
};
Expand All @@ -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<failure::Error>),
/// 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),
Expand All @@ -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 {
Expand All @@ -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<failure::Error>) -> Error {
let error = Arc::new(cause.into());
Self::from(ErrorKind::MalformedContent(error))
Expand Down Expand Up @@ -100,14 +119,29 @@ impl From<ErrorKind> for Error {
}
}

impl<T: std::error::Error + Send + Sync + 'static> From<T> for Error {
#[cfg(not(feature = "std"))]
impl From<FromUtf8Error> for Error {
fn from(_: FromUtf8Error) -> Self {
Self::from(ErrorKind::MalformedContent)
}
}

#[cfg(not(feature = "std"))]
impl From<ParseIntError> for Error {
fn from(_: ParseIntError) -> Self {
Self::from(ErrorKind::MalformedContent)
}
}

#[cfg(feature = "std")]
impl<T: StdError + Send + Sync + 'static> From<T> for Error {
fn from(error: T) -> Self {
Self::malformed_content(error)
}
}

impl<T> ResultExt for Result<T, Error> {
fn context(self, context: impl std::fmt::Display) -> Result<T, Error> {
fn context(self, context: impl Display) -> Result<T, Error> {
self.map_err(|err| err.context(context))
}
}
Loading