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

View file

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

View file

@ -34,8 +34,8 @@
//!
//! `use_std`: Use standard library. Enabled by default, disable for no_std.
//!
//! `typed`: Enables the [`typed`](typed/index.html) sub-module for sending and
//! receiving structs serialized with serde. Enabled by default.
//! `use_nightly`: Enables unstable features that only work on nightly rust.
//! Required for practical no_std use.
//!
//! `trace`: Enable to print all data to stdout for testing.
//!
@ -118,6 +118,10 @@
//!
//! // The maximum payload length implies a maximum encoded frame length,
//! // 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);
//!
//! let payload: [u8; 3] = [1, 2, 3];
@ -140,8 +144,95 @@
#![deny(warnings)]
#![cfg_attr(not(feature = "use_std"), no_std)]
// TODO: Disable this when toolchain != nightly.
#![feature(const_fn)]
#![cfg_attr(feature = "use_nightly", 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 cobs;
@ -151,14 +242,12 @@ extern crate core;
extern crate ref_slice;
#[cfg(feature = "typed")]
extern crate serde;
#[macro_use]
#[cfg(all(test, feature = "typed", feature = "use_std"))]
#[cfg(all(test, feature = "use_std"))]
extern crate serde_derive;
#[cfg(feature = "typed")]
extern crate ssmarshal;
@ -169,7 +258,6 @@ pub mod channel;
pub mod error;
pub use error::{Error, Result};
#[cfg(all(feature = "typed", feature = "use_std"))]
pub mod typed;
// ## use statements
@ -406,34 +494,39 @@ pub fn decode_from_reader<R: Read>(r: &mut Read) -> Result<BoxPayload> {
decode_to_box(&*next_frame)
}
/// 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 {
const_fn! {
/// 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 fn max_decoded_len(code_len: usize) -> usize {
// This is an over-estimate of the required decoded buffer, but
// wasting HEADER_LEN + FOOTER_LEN bytes should be acceptable and
// we can calculate this trivially in a const fn.
code_len
}
}
/// 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 {
const_fn! {
/// Returns an upper bound for the encoded length of a frame with
/// the payload length supplied.
///
/// Useful for calculating an appropriate buffer length.
pub fn max_encoded_len(payload_len: usize) -> usize {
HEADER_LEN
+ cobs_max_encoded_len(payload_len)
+ FOOTER_LEN
}
}
/// Copied from `cobs` crate to make a `const` version.
///
/// 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
const fn cobs_max_encoded_len(payload_len: usize) -> usize {
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
///
/// 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
fn cobs_max_encoded_len(payload_len: usize) -> usize {
payload_len
+ (payload_len / 254)
@ -443,23 +536,8 @@ const fn cobs_max_encoded_len(payload_len: usize) -> usize {
// 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
// time.
//
// 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.

View file

@ -93,6 +93,7 @@
use ::{Encoded, TempBuffer};
use ::error::{Result};
#[cfg(feature = "use_std")]
use core::marker::PhantomData;
use core::mem::size_of;
use serde::Serialize;
@ -160,23 +161,27 @@ pub fn decode_from_slice<T: DeserializeOwned + Serialize>(
Ok(v)
}
/// 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 {
const_fn! {
/// 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 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
/// length needed by `encode_to_slice` and `decode_from_slice` when
/// serializing or deserializing a value of type `T`.
pub const fn max_serialize_buf_len<T: DeserializeOwned + Serialize>() -> usize {
const_fn! {
/// Returns an upper bound for the temporary serialization buffer
/// length needed by `encode_to_slice` and `decode_from_slice` when
/// serializing or deserializing a value of type `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
///
@ -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 {
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
///
@ -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 {
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.
pub fn recv(&mut self) -> Result<T> {
let payload = super::decode_from_reader::<R>(&mut self.r)?;