1
Fork 0

New feature flag "use_nightly", const_fn! macro using it, drop feature flag "typed".

This commit is contained in:
Alex Helfet 2017-12-29 00:48:41 +00:00
parent 98582cc9ae
commit 2cbf1bbb60
4 changed files with 162 additions and 82 deletions

View file

@ -19,14 +19,14 @@ branch = "master"
[dependencies] [dependencies]
cobs = "^0.1.3" cobs = "^0.1.3"
ref_slice = "^1.1.1" ref_slice = "^1.1.1"
serde = { version = "^1.0", optional = true } serde = "^1.0"
ssmarshal = { version = "^1.0", optional = true } ssmarshal = "^1.0"
[dev-dependencies] [dev-dependencies]
serde_derive = "^1.0" serde_derive = "^1.0"
[features] [features]
default = ["use_std", "typed"] default = ["use_std"]
# Enable to print all data to stdout for testing. # Enable to print all data to stdout for testing.
trace = [] trace = []
@ -34,6 +34,6 @@ trace = []
# Use standard library. Enabled by default, disable for no_std. # Use standard library. Enabled by default, disable for no_std.
use_std = [] use_std = []
# Enables the `typed` sub-module for sending and receiving # Enables unstable features that only work on nightly rust.
# structs serialized with serde. # Required for practical no_std use.
typed = ["serde", "ssmarshal"] use_nightly = []

View file

@ -1,6 +1,5 @@
//! Representations of errors returned by this crate. //! Representations of errors returned by this crate.
#[cfg(feature = "typed")]
use ssmarshal; use ssmarshal;
#[cfg(feature = "use_std")] #[cfg(feature = "use_std")]
@ -35,7 +34,6 @@ pub enum Error {
Io(io::Error), Io(io::Error),
/// Forwarded ssmarshal::Error. /// Forwarded ssmarshal::Error.
#[cfg(feature = "typed")]
Ssmarshal(ssmarshal::Error), Ssmarshal(ssmarshal::Error),
} }
@ -46,7 +44,6 @@ impl From<io::Error> for Error {
} }
} }
#[cfg(feature = "typed")]
impl From<ssmarshal::Error> for Error { impl From<ssmarshal::Error> for Error {
fn from(e: ssmarshal::Error) -> Error { fn from(e: ssmarshal::Error) -> Error {
Error::Ssmarshal(e) Error::Ssmarshal(e)

View file

@ -34,8 +34,8 @@
//! //!
//! `use_std`: Use standard library. Enabled by default, disable for no_std. //! `use_std`: Use standard library. Enabled by default, disable for no_std.
//! //!
//! `typed`: Enables the [`typed`](typed/index.html) sub-module for sending and //! `use_nightly`: Enables unstable features that only work on nightly rust.
//! receiving structs serialized with serde. Enabled by default. //! Required for practical no_std use.
//! //!
//! `trace`: Enable to print all data to stdout for testing. //! `trace`: Enable to print all data to stdout for testing.
//! //!
@ -118,6 +118,10 @@
//! //!
//! // The maximum payload length implies a maximum encoded frame length, //! // The maximum payload length implies a maximum encoded frame length,
//! // which we can use for frame buffers. //! // which we can use for frame buffers.
//! //
//! // Using a calculated frame buffer length like this requires
//! // const fn, which is currently unstable and only available on nightly rust.
//! // Enable cargo feature flag "use_nightly" to use it.
//! const MAX_FRAME_LEN: usize = max_encoded_len(MAX_PAYLOAD_LEN); //! const MAX_FRAME_LEN: usize = max_encoded_len(MAX_PAYLOAD_LEN);
//! //!
//! let payload: [u8; 3] = [1, 2, 3]; //! let payload: [u8; 3] = [1, 2, 3];
@ -140,8 +144,95 @@
#![deny(warnings)] #![deny(warnings)]
#![cfg_attr(not(feature = "use_std"), no_std)] #![cfg_attr(not(feature = "use_std"), no_std)]
// TODO: Disable this when toolchain != nightly. #![cfg_attr(feature = "use_nightly", feature(const_fn))]
#![feature(const_fn)]
/// Macro const_fn! declares a function
/// with `pub fn` when feature "use_nightly" is disabled, and
/// with `pub const fn` when feature "use_nightly" is enabled.
///
/// Usage:
/// ```ignore
/// const_fn! {
/// fn foo() {
/// println!("Hello, world!");
/// }
/// }
/// ```
#[cfg(feature = "use_nightly")]
macro_rules! const_fn {
($(#[$attr: meta])*
pub fn $name:ident
<$($gen_ty_name:ident : $gen_ty_ty:path),+>
($($arg_name:ident : $arg_ty: ty),*)
-> $ret_ty:ty
$body: block) =>
($(#[$attr])*
pub const fn $name
<$($gen_ty_name : $gen_ty_ty),*>
($($arg_name : $arg_ty),*)
-> $ret_ty
$body);
($(#[$attr: meta])*
pub fn $name:ident
($($arg_name:ident : $arg_ty: ty),*)
-> $ret_ty:ty
$body: block) =>
($(#[$attr])*
pub const fn $name
($($arg_name : $arg_ty),*)
-> $ret_ty
$body);
($(#[$attr: meta])*
fn $name:ident
($($arg_name:ident : $arg_ty: ty),*)
-> $ret_ty:ty
$body: block) =>
($(#[$attr])*
const fn $name
($($arg_name : $arg_ty),*)
-> $ret_ty
$body);
}
#[cfg(not(feature = "use_nightly"))]
macro_rules! const_fn {
($(#[$attr: meta])*
pub fn $name:ident
<$($gen_ty_name:ident : $gen_ty_ty:path),+>
($($arg_name:ident : $arg_ty: ty),*)
-> $ret_ty:ty
$body: block) =>
($(#[$attr])*
pub fn $name
<$($gen_ty_name : $gen_ty_ty),*>
($($arg_name : $arg_ty),*)
-> $ret_ty
$body);
($(#[$attr: meta])*
pub fn $name:ident
($($arg_name:ident : $arg_ty: ty),*)
-> $ret_ty:ty
$body: block) =>
($(#[$attr])*
pub fn $name
($($arg_name : $arg_ty),*)
-> $ret_ty
$body);
($(#[$attr: meta])*
fn $name:ident
($($arg_name:ident : $arg_ty: ty),*)
-> $ret_ty:ty
$body: block) =>
($(#[$attr])*
fn $name
($($arg_name : $arg_ty),*)
-> $ret_ty
$body);
}
// ## extern crate statements // ## extern crate statements
extern crate cobs; extern crate cobs;
@ -151,14 +242,12 @@ extern crate core;
extern crate ref_slice; extern crate ref_slice;
#[cfg(feature = "typed")]
extern crate serde; extern crate serde;
#[macro_use] #[macro_use]
#[cfg(all(test, feature = "typed", feature = "use_std"))] #[cfg(all(test, feature = "use_std"))]
extern crate serde_derive; extern crate serde_derive;
#[cfg(feature = "typed")]
extern crate ssmarshal; extern crate ssmarshal;
@ -169,7 +258,6 @@ pub mod channel;
pub mod error; pub mod error;
pub use error::{Error, Result}; pub use error::{Error, Result};
#[cfg(all(feature = "typed", feature = "use_std"))]
pub mod typed; pub mod typed;
// ## use statements // ## use statements
@ -406,60 +494,50 @@ pub fn decode_from_reader<R: Read>(r: &mut Read) -> Result<BoxPayload> {
decode_to_box(&*next_frame) decode_to_box(&*next_frame)
} }
/// Returns an upper bound for the decoded length of the payload const_fn! {
/// within a frame with the encoded length supplied. /// Returns an upper bound for the decoded length of the payload
/// /// within a frame with the encoded length supplied.
/// Useful for calculating an appropriate buffer length. ///
pub const fn max_decoded_len(code_len: usize) -> usize { /// Useful for calculating an appropriate buffer length.
// This is an over-estimate of the required decoded buffer, but pub fn max_decoded_len(code_len: usize) -> usize {
// wasting HEADER_LEN + FOOTER_LEN bytes should be acceptable and // This is an over-estimate of the required decoded buffer, but
// we can calculate this trivially in a const fn. // wasting HEADER_LEN + FOOTER_LEN bytes should be acceptable and
code_len // we can calculate this trivially in a const fn.
code_len
}
} }
/// Returns an upper bound for the encoded length of a frame with const_fn! {
/// the payload length supplied. /// Returns an upper bound for the encoded length of a frame with
/// /// the payload length supplied.
/// Useful for calculating an appropriate buffer length. ///
pub const fn max_encoded_len(payload_len: usize) -> usize { /// Useful for calculating an appropriate buffer length.
HEADER_LEN pub fn max_encoded_len(payload_len: usize) -> usize {
+ cobs_max_encoded_len(payload_len) HEADER_LEN
+ FOOTER_LEN + cobs_max_encoded_len(payload_len)
+ FOOTER_LEN
}
} }
/// Copied from `cobs` crate to make a `const` version. const_fn! {
/// /// Copied from `cobs` crate and modified to make a `const` version.
/// Source: https://github.com/awelkie/cobs.rs/blob/f8ff1ad2aa7cd069a924d75170d3def3fa6df10b/src/lib.rs#L183-L188 ///
/// /// Source: https://github.com/awelkie/cobs.rs/blob/f8ff1ad2aa7cd069a924d75170d3def3fa6df10b/src/lib.rs#L183-L188
/// TODO: Submit a PR to `cobs` to make `cobs::max_encoding_length` a `const fn`. ///
/// Issue for this: https://github.com/fluffysquirrels/framed-rs/issues/19 /// TODO: Submit a PR to `cobs` to make `cobs::max_encoding_length` a `const fn`.
const fn cobs_max_encoded_len(payload_len: usize) -> usize { /// Issue for this: https://github.com/fluffysquirrels/framed-rs/issues/19
payload_len fn cobs_max_encoded_len(payload_len: usize) -> usize {
+ (payload_len / 254) payload_len
+ (payload_len / 254)
// This `+ 1` was // This `+ 1` was
// `+ if payload_len % 254 > 0 { 1 } else { 0 }` in cobs.rs, // `+ if payload_len % 254 > 0 { 1 } else { 0 }` in cobs.rs,
// but that won't compile in a const fn. `1` is less than both the // but that won't compile in a const fn. `1` is less than both the
// values in the if and else branches, so use that instead, with the // values in the if and else branches, so use that instead, with the
// acceptable cost of allocating 1 byte more than required some of the // acceptable cost of allocating 1 byte more than required some of the
// time. // time.
// + 1
// const fn compiler error was: }
// ```
// error[E0019]: constant function contains unimplemented expression type
// --> framed/src/lib.rs:388:11
// |
// 388 | + if payload_len % 254 > 0 { 1 } else { 0 }
// | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
//
// error: aborting due to previous error
// ```
//
// Relevant section of const fn design doc:
// https://github.com/rust-lang/rfcs/blob/5f69ff50de1fb6d0dd8c005b4f11f6e436e1f34c/text/0911-const-fn.md#detailed-design
// const fn tracking issue: https://github.com/rust-lang/rust/issues/24111
+ 1
} }
/// Sends encoded frames over an inner `std::io::Write` instance. /// Sends encoded frames over an inner `std::io::Write` instance.

View file

@ -93,6 +93,7 @@
use ::{Encoded, TempBuffer}; use ::{Encoded, TempBuffer};
use ::error::{Result}; use ::error::{Result};
#[cfg(feature = "use_std")]
use core::marker::PhantomData; use core::marker::PhantomData;
use core::mem::size_of; use core::mem::size_of;
use serde::Serialize; use serde::Serialize;
@ -160,23 +161,27 @@ pub fn decode_from_slice<T: DeserializeOwned + Serialize>(
Ok(v) Ok(v)
} }
/// Returns an upper bound for the encoded length of a frame with a const_fn! {
/// serialized `T` value as its payload. /// Returns an upper bound for the encoded length of a frame with a
/// /// serialized `T` value as its payload.
/// Useful for calculating an appropriate buffer length. ///
pub const fn max_encoded_len<T: DeserializeOwned + Serialize>() -> usize { /// Useful for calculating an appropriate buffer length.
super::max_encoded_len(max_serialize_buf_len::<T>()) pub fn max_encoded_len<T: Serialize>() -> usize {
super::max_encoded_len(max_serialize_buf_len::<T>())
}
} }
/// Returns an upper bound for the temporary serialization buffer const_fn! {
/// length needed by `encode_to_slice` and `decode_from_slice` when /// Returns an upper bound for the temporary serialization buffer
/// serializing or deserializing a value of type `T`. /// length needed by `encode_to_slice` and `decode_from_slice` when
pub const fn max_serialize_buf_len<T: DeserializeOwned + Serialize>() -> usize { /// serializing or deserializing a value of type `T`.
super::max_encoded_len(size_of::<T>()) pub fn max_serialize_buf_len<T: Serialize>() -> usize {
super::max_encoded_len(size_of::<T>())
}
} }
/// Sends encoded structs of type `T` over an inner `io::Write` instance. /// Sends encoded structs of type `T` over an inner `std::io::Write` instance.
/// ///
/// ## Examples /// ## Examples
/// ///
@ -199,7 +204,7 @@ impl<W: Write, T: Serialize> Sender<W, T> {
} }
} }
/// Consume this `Sender` and return the inner `io::Write`. /// Consume this `Sender` and return the inner `std::io::Write`.
pub fn into_inner(self) -> W { pub fn into_inner(self) -> W {
self.w self.w
} }
@ -253,7 +258,7 @@ impl<W: Write, T: Serialize> Sender<W, T> {
} }
} }
/// Receives encoded structs of type `T` from an inner `io::Read` instance. /// Receives encoded structs of type `T` from an inner `std::io::Read` instance.
/// ///
/// ## Examples /// ## Examples
/// ///
@ -276,12 +281,12 @@ impl<R: Read, T: DeserializeOwned> Receiver<R, T> {
} }
} }
/// Consume this `Receiver` and return the inner `io::Read`. /// Consume this `Receiver` and return the inner `std::io::Read`.
pub fn into_inner(self) -> R { pub fn into_inner(self) -> R {
self.r self.r
} }
/// Receive an encoded frame from the inner `io::Read`, decode it /// Receive an encoded frame from the inner `std::io::Read`, decode it
/// and return the payload. /// and return the payload.
pub fn recv(&mut self) -> Result<T> { pub fn recv(&mut self) -> Result<T> {
let payload = super::decode_from_reader::<R>(&mut self.r)?; let payload = super::decode_from_reader::<R>(&mut self.r)?;