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]
|
||||
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 = []
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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)?;
|
||||
|
|
Loading…
Reference in a new issue