New feature flag "use_nightly", const_fn! macro using it, drop feature flag "typed".
This commit is contained in:
parent
98582cc9ae
commit
2cbf1bbb60
4 changed files with 162 additions and 82 deletions
|
@ -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 = []
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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)?;
|
||||||
|
|
Loading…
Reference in a new issue