From 9857d1bb5467488d725f29f13eb63ea057b697c7 Mon Sep 17 00:00:00 2001 From: Tony Arcieri Date: Fri, 16 Jun 2017 16:00:54 -0700 Subject: [PATCH] Support no_std w\ enabled-by-default "use_std" feature - Changes all references to libcore features from ::std to ::core - Feature gates anything dependent on std::io on the "use_std" feature - Obtains Box, String, and Vec from libcollections in no_std environments - Vendors a tiny bit of std::io::cursor for use in no_std environments --- .travis.yml | 4 ++++ Cargo.toml | 9 +++++++- src/buf/buf.rs | 14 ++++++++++-- src/buf/buf_mut.rs | 18 ++++++++++++--- src/buf/chain.rs | 3 +++ src/buf/cursor.rs | 54 +++++++++++++++++++++++++++++++++++++++++++++ src/buf/from_buf.rs | 3 +++ src/buf/into_buf.rs | 33 ++++++++++++++++----------- src/buf/mod.rs | 4 ++++ src/buf/reader.rs | 2 ++ src/buf/take.rs | 2 +- src/buf/writer.rs | 2 ++ src/bytes.rs | 22 +++++++++++++----- src/debug.rs | 2 +- src/lib.rs | 7 ++++++ 15 files changed, 152 insertions(+), 27 deletions(-) create mode 100644 src/buf/cursor.rs diff --git a/.travis.yml b/.travis.yml index eb0d1eb58..fa72afa03 100644 --- a/.travis.yml +++ b/.travis.yml @@ -36,6 +36,10 @@ matrix: # Serde implementation - env: EXTRA_ARGS="--features serde" + # Ensure crate compiles without default features (i.e. for no_std) + - script: cargo build --no-default-features + rust: nightly + before_install: set -e install: diff --git a/Cargo.toml b/Cargo.toml index d1b585c6a..ca1af38c6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,8 +21,15 @@ categories = ["network-programming", "data-structures"] [dependencies] byteorder = "1.0.0" -iovec = "0.1" serde = { version = "1.0", optional = true } +[dependencies.iovec] +version = "0.1" +optional = true + [dev-dependencies] serde_test = "1.0" + +[features] +default = ["use_std"] +use_std = ["iovec"] diff --git a/src/buf/buf.rs b/src/buf/buf.rs index 42280e793..55253a9d6 100644 --- a/src/buf/buf.rs +++ b/src/buf/buf.rs @@ -1,8 +1,15 @@ use super::{IntoBuf, Take, Reader, Iter, FromBuf, Chain}; use byteorder::ByteOrder; +#[cfg(feature = "use_std")] use iovec::IoVec; -use std::{cmp, io, ptr}; +#[cfg(not(feature = "use_std"))] +use collections::boxed::Box; +use core::{cmp, ptr}; +#[cfg(not(feature = "use_std"))] +use buf::Cursor; +#[cfg(feature = "use_std")] +use std::io::Cursor; /// Read bytes from a buffer. /// @@ -113,6 +120,7 @@ pub trait Buf { /// with `dst` being a zero length slice. /// /// [`writev`]: http://man7.org/linux/man-pages/man2/readv.2.html + #[cfg(feature = "use_std")] fn bytes_vec<'a>(&'a self, dst: &mut [&'a IoVec]) -> usize { if dst.is_empty() { return 0; @@ -662,6 +670,7 @@ impl<'a, T: Buf + ?Sized> Buf for &'a mut T { (**self).bytes() } + #[cfg(feature = "use_std")] fn bytes_vec<'b>(&'b self, dst: &mut [&'b IoVec]) -> usize { (**self).bytes_vec(dst) } @@ -680,6 +689,7 @@ impl Buf for Box { (**self).bytes() } + #[cfg(feature = "use_std")] fn bytes_vec<'b>(&'b self, dst: &mut [&'b IoVec]) -> usize { (**self).bytes_vec(dst) } @@ -689,7 +699,7 @@ impl Buf for Box { } } -impl> Buf for io::Cursor { +impl> Buf for Cursor { fn remaining(&self) -> usize { let len = self.get_ref().as_ref().len(); let pos = self.position(); diff --git a/src/buf/buf_mut.rs b/src/buf/buf_mut.rs index b03103a61..764ed8401 100644 --- a/src/buf/buf_mut.rs +++ b/src/buf/buf_mut.rs @@ -1,8 +1,17 @@ use super::{IntoBuf, Writer}; use byteorder::ByteOrder; +#[cfg(feature = "use_std")] use iovec::IoVec; -use std::{cmp, io, ptr, usize}; +#[cfg(not(feature = "use_std"))] +use collections::boxed::Box; +#[cfg(not(feature = "use_std"))] +use collections::vec::Vec; +use core::{cmp, ptr, usize}; +#[cfg(not(feature = "use_std"))] +use buf::Cursor; +#[cfg(feature = "use_std")] +use std::io::Cursor; /// A trait for values that provide sequential write access to bytes. /// @@ -188,6 +197,7 @@ pub trait BufMut { /// with `dst` being a zero length slice. /// /// [`readv`]: http://man7.org/linux/man-pages/man2/readv.2.html + #[cfg(feature = "use_std")] unsafe fn bytes_vec_mut<'a>(&'a mut self, dst: &mut [&'a mut IoVec]) -> usize { if dst.is_empty() { return 0; @@ -645,6 +655,7 @@ impl<'a, T: BufMut + ?Sized> BufMut for &'a mut T { (**self).bytes_mut() } + #[cfg(feature = "use_std")] unsafe fn bytes_vec_mut<'b>(&'b mut self, dst: &mut [&'b mut IoVec]) -> usize { (**self).bytes_vec_mut(dst) } @@ -663,6 +674,7 @@ impl BufMut for Box { (**self).bytes_mut() } + #[cfg(feature = "use_std")] unsafe fn bytes_vec_mut<'b>(&'b mut self, dst: &mut [&'b mut IoVec]) -> usize { (**self).bytes_vec_mut(dst) } @@ -672,7 +684,7 @@ impl BufMut for Box { } } -impl + AsRef<[u8]>> BufMut for io::Cursor { +impl + AsRef<[u8]>> BufMut for Cursor { fn remaining_mut(&self) -> usize { use Buf; self.remaining() @@ -721,7 +733,7 @@ impl BufMut for Vec { #[inline] unsafe fn bytes_mut(&mut self) -> &mut [u8] { - use std::slice; + use core::slice; if self.capacity() == self.len() { self.reserve(64); // Grow the vec diff --git a/src/buf/chain.rs b/src/buf/chain.rs index 7dd44ab02..3465cabb4 100644 --- a/src/buf/chain.rs +++ b/src/buf/chain.rs @@ -1,4 +1,5 @@ use {Buf, BufMut}; +#[cfg(feature = "use_std")] use iovec::IoVec; /// A `Chain` sequences two buffers. @@ -177,6 +178,7 @@ impl Buf for Chain self.b.advance(cnt); } + #[cfg(feature = "use_std")] fn bytes_vec<'a>(&'a self, dst: &mut [&'a IoVec]) -> usize { let mut n = self.a.bytes_vec(dst); n += self.b.bytes_vec(&mut dst[n..]); @@ -218,6 +220,7 @@ impl BufMut for Chain self.b.advance_mut(cnt); } + #[cfg(feature = "use_std")] unsafe fn bytes_vec_mut<'a>(&'a mut self, dst: &mut [&'a mut IoVec]) -> usize { let mut n = self.a.bytes_vec_mut(dst); n += self.b.bytes_vec_mut(&mut dst[n..]); diff --git a/src/buf/cursor.rs b/src/buf/cursor.rs new file mode 100644 index 000000000..4feee58f2 --- /dev/null +++ b/src/buf/cursor.rs @@ -0,0 +1,54 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +/// A `Cursor` wraps another type and provides it with a +/// [`Seek`] implementation. +/// +/// `Cursor`s are typically used with in-memory buffers to allow them to +/// implement [`Read`] and/or [`Write`], allowing these buffers to be used +/// anywhere you might use a reader or writer that does actual I/O. +/// +/// The standard library implements some I/O traits on various types which +/// are commonly used as a buffer, like `Cursor<`[`Vec`]`>` and +/// `Cursor<`[`&[u8]`][bytes]`>`. +#[derive(Clone, Debug)] +pub struct Cursor { + inner: T, + pos: u64, +} + +impl Cursor { + /// Creates a new cursor wrapping the provided underlying I/O object. + /// + /// Cursor initial position is `0` even if underlying object (e. + /// g. `Vec`) is not empty. So writing to cursor starts with + /// overwriting `Vec` content, not with appending to it. + pub fn new(inner: T) -> Cursor { + Cursor { pos: 0, inner: inner } + } + + /// Consumes this cursor, returning the underlying value. + pub fn into_inner(self) -> T { self.inner } + + /// Gets a reference to the underlying value in this cursor. + pub fn get_ref(&self) -> &T { &self.inner } + + /// Gets a mutable reference to the underlying value in this cursor. + /// + /// Care should be taken to avoid modifying the internal I/O state of the + /// underlying value as it may corrupt this cursor's position. + pub fn get_mut(&mut self) -> &mut T { &mut self.inner } + + /// Returns the current position of this cursor. + pub fn position(&self) -> u64 { self.pos } + + /// Sets the position of this cursor. + pub fn set_position(&mut self, pos: u64) { self.pos = pos; } +} diff --git a/src/buf/from_buf.rs b/src/buf/from_buf.rs index 55f5cef31..9c6248b35 100644 --- a/src/buf/from_buf.rs +++ b/src/buf/from_buf.rs @@ -1,5 +1,8 @@ use {Buf, BufMut, IntoBuf, Bytes, BytesMut}; +#[cfg(not(feature = "use_std"))] +use collections::vec::Vec; + /// Conversion from a [`Buf`] /// /// Implementing `FromBuf` for a type defines how it is created from a buffer. diff --git a/src/buf/into_buf.rs b/src/buf/into_buf.rs index 1071908a2..ef23b163a 100644 --- a/src/buf/into_buf.rs +++ b/src/buf/into_buf.rs @@ -1,6 +1,13 @@ use super::{Buf}; -use std::io; +#[cfg(not(feature = "use_std"))] +use buf::Cursor; +#[cfg(not(feature = "use_std"))] +use collections::string::String; +#[cfg(not(feature = "use_std"))] +use collections::vec::Vec; +#[cfg(feature = "use_std")] +use std::io::Cursor; /// Conversion into a `Buf` /// @@ -56,15 +63,15 @@ impl IntoBuf for T { } impl<'a> IntoBuf for &'a [u8] { - type Buf = io::Cursor<&'a [u8]>; + type Buf = Cursor<&'a [u8]>; fn into_buf(self) -> Self::Buf { - io::Cursor::new(self) + Cursor::new(self) } } impl<'a> IntoBuf for &'a str { - type Buf = io::Cursor<&'a [u8]>; + type Buf = Cursor<&'a [u8]>; fn into_buf(self) -> Self::Buf { self.as_bytes().into_buf() @@ -72,33 +79,33 @@ impl<'a> IntoBuf for &'a str { } impl IntoBuf for Vec { - type Buf = io::Cursor>; + type Buf = Cursor>; fn into_buf(self) -> Self::Buf { - io::Cursor::new(self) + Cursor::new(self) } } impl<'a> IntoBuf for &'a Vec { - type Buf = io::Cursor<&'a [u8]>; + type Buf = Cursor<&'a [u8]>; fn into_buf(self) -> Self::Buf { - io::Cursor::new(&self[..]) + Cursor::new(&self[..]) } } // Kind of annoying... but this impl is required to allow passing `&'static // [u8]` where for<'a> &'a T: IntoBuf is required. impl<'a> IntoBuf for &'a &'static [u8] { - type Buf = io::Cursor<&'static [u8]>; + type Buf = Cursor<&'static [u8]>; fn into_buf(self) -> Self::Buf { - io::Cursor::new(self) + Cursor::new(self) } } impl<'a> IntoBuf for &'a &'static str { - type Buf = io::Cursor<&'static [u8]>; + type Buf = Cursor<&'static [u8]>; fn into_buf(self) -> Self::Buf { self.as_bytes().into_buf() @@ -106,7 +113,7 @@ impl<'a> IntoBuf for &'a &'static str { } impl IntoBuf for String { - type Buf = io::Cursor>; + type Buf = Cursor>; fn into_buf(self) -> Self::Buf { self.into_bytes().into_buf() @@ -114,7 +121,7 @@ impl IntoBuf for String { } impl<'a> IntoBuf for &'a String { - type Buf = io::Cursor<&'a [u8]>; + type Buf = Cursor<&'a [u8]>; fn into_buf(self) -> Self::Buf { self.as_bytes().into_buf() diff --git a/src/buf/mod.rs b/src/buf/mod.rs index 1f74e0ab4..63a9a3018 100644 --- a/src/buf/mod.rs +++ b/src/buf/mod.rs @@ -20,6 +20,8 @@ mod buf; mod buf_mut; mod from_buf; mod chain; +#[cfg(not(feature = "use_std"))] +mod cursor; mod into_buf; mod iter; mod reader; @@ -30,6 +32,8 @@ pub use self::buf::Buf; pub use self::buf_mut::BufMut; pub use self::from_buf::FromBuf; pub use self::chain::Chain; +#[cfg(not(feature = "use_std"))] +pub use self::cursor::Cursor; pub use self::into_buf::IntoBuf; pub use self::iter::Iter; pub use self::reader::Reader; diff --git a/src/buf/reader.rs b/src/buf/reader.rs index 59f9c3304..c1b83906c 100644 --- a/src/buf/reader.rs +++ b/src/buf/reader.rs @@ -1,5 +1,6 @@ use {Buf}; +#[cfg(feature = "use_std")] use std::{cmp, io}; /// A `Buf` adapter which implements `io::Read` for the inner value. @@ -78,6 +79,7 @@ impl Reader { } } +#[cfg(feature = "use_std")] impl io::Read for Reader { fn read(&mut self, dst: &mut [u8]) -> io::Result { let len = cmp::min(self.buf.remaining(), dst.len()); diff --git a/src/buf/take.rs b/src/buf/take.rs index 53c2933e9..fe0e117b6 100644 --- a/src/buf/take.rs +++ b/src/buf/take.rs @@ -1,6 +1,6 @@ use {Buf}; -use std::cmp; +use core::cmp; /// A `Buf` adapter which limits the bytes read from an underlying buffer. /// diff --git a/src/buf/writer.rs b/src/buf/writer.rs index 38a739aa6..a3f99bc14 100644 --- a/src/buf/writer.rs +++ b/src/buf/writer.rs @@ -1,5 +1,6 @@ use BufMut; +#[cfg(feature = "use_std")] use std::{cmp, io}; /// A `BufMut` adapter which implements `io::Write` for the inner value. @@ -74,6 +75,7 @@ impl Writer { } } +#[cfg(feature = "use_std")] impl io::Write for Writer { fn write(&mut self, src: &[u8]) -> io::Result { let n = cmp::min(self.buf.remaining_mut(), src.len()); diff --git a/src/bytes.rs b/src/bytes.rs index fd0317dff..34d5cac16 100644 --- a/src/bytes.rs +++ b/src/bytes.rs @@ -2,11 +2,21 @@ use {IntoBuf, Buf, BufMut}; use buf::Iter; use debug; -use std::{cmp, fmt, mem, hash, ops, slice, ptr, usize}; -use std::borrow::Borrow; +use core::{cmp, fmt, mem, hash, ops, slice, ptr, usize}; +use core::borrow::Borrow; +use core::sync::atomic::{self, AtomicUsize, AtomicPtr}; +use core::sync::atomic::Ordering::{Relaxed, Acquire, Release, AcqRel}; + +#[cfg(not(feature = "use_std"))] +use buf::Cursor; +#[cfg(not(feature = "use_std"))] +use collections::boxed::Box; +#[cfg(not(feature = "use_std"))] +use collections::string::String; +#[cfg(not(feature = "use_std"))] +use collections::vec::Vec; +#[cfg(feature = "use_std")] use std::io::Cursor; -use std::sync::atomic::{self, AtomicUsize, AtomicPtr}; -use std::sync::atomic::Ordering::{Relaxed, Acquire, Release, AcqRel}; /// A reference counted contiguous slice of memory. /// @@ -320,10 +330,10 @@ struct Inner2 { } // Thread-safe reference-counted container for the shared storage. This mostly -// the same as `std::sync::Arc` but without the weak counter. The ref counting +// the same as `core::sync::Arc` but without the weak counter. The ref counting // fns are based on the ones found in `std`. // -// The main reason to use `Shared` instead of `std::sync::Arc` is that it ends +// The main reason to use `Shared` instead of `core::sync::Arc` is that it ends // up making the overall code simpler and easier to reason about. This is due to // some of the logic around setting `Inner::arc` and other ways the `arc` field // is used. Using `Arc` ended up requiring a number of funky transmutes and diff --git a/src/debug.rs b/src/debug.rs index abead058a..9f4cbfb9a 100644 --- a/src/debug.rs +++ b/src/debug.rs @@ -1,4 +1,4 @@ -use std::fmt; +use core::fmt; /// Alternative implementation of `fmt::Debug` for byte slice. /// diff --git a/src/lib.rs b/src/lib.rs index fbe65721a..01aace716 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -70,8 +70,15 @@ #![deny(warnings, missing_docs, missing_debug_implementations)] #![doc(html_root_url = "https://docs.rs/bytes/0.4")] +#![cfg_attr(not(feature = "use_std"), no_std)] +#![cfg_attr(not(feature = "use_std"), feature(collections))] extern crate byteorder; +#[cfg(not(feature = "use_std"))] +extern crate collections; +#[cfg(feature = "use_std")] +extern crate core; +#[cfg(feature = "use_std")] extern crate iovec; pub mod buf;