1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
#![deny(missing_docs)]
#![feature(custom_attribute)]

//! # Approach
//! This crate is meant to provide two methods for serializing and deserializing with buffer
//! operations:
//! * The `copy` module is a more flexible, high-level stream based approach for reading from and
//! writing to buffers. This will introduce some overhead so do not use this if copies are a bottleneck.
//! * The `nocopy` module is a more restrictive macro-based approach. It uses procedural macros and
//! unions to provide some level of safety when writing to fields in a struct while allowing the
//! underlying struct to be interpreted as a slice. This is a C-like workflow but does provide
//! some helpful guarantees that come with Rust like protection against buffer overflows and
//! bounds checking. One very important note is the notion that structs that use the provided
//! procedural macro must be completely allocatable on the stack. Compilation will fail if certain
//! constructs that prevent size computation at compile time are used. As a result this really
//! should only be used as an optimization for a more type safe common C workflow in very low level
//! scenarios.
//!
//! # Features
//! Each module is feature-flagged at build time to avoid pulling in unnecessary code if only one is
//! necessary.  Available features are:
//! * `copy`
//! * `nocopy`

/// A more restrictive macro-based approach to serializing and deserializing into buffers with some
/// unsafe code to remove copy overhead
#[cfg(feature = "nocopy")]
#[macro_use]
#[allow(unused_imports)]
extern crate buffering_nocopy_macro;

/// A more flexible way to serialize and deserialize into buffers that will have some copy overhead
#[cfg(feature = "copy")]
pub mod copy;

#[cfg(feature = "copy")]
pub use copy::*;

#[cfg(all(test, nocopy))]
mod test {
    use std::mem;

    #[test]
    fn test_proc_macro() {
        #[derive(Copy,Clone,NoCopy)]
        #[name = "TestBufferThing"]
        pub struct Test {
            test: u8,
        }

        let mut tb = TestBufferThing::new_buffer([0]);
        tb.set_test(5);
        assert_eq!(tb.as_buffer(), [5]);

        #[derive(Copy,Clone,NoCopy)]
        #[name = "TestBufferThingTwo"]
        pub struct TestTwo {
            #[endian = "big"]
            test: u16,
        }

        let tb = TestBufferThingTwo::new_buffer([0, 5]);
        assert_eq!(tb.get_test(), 5);

        #[derive(Copy,Clone,NoCopy)]
        #[name = "TestBufferThingThree"]
        pub struct TestThree {
            #[endian = "little"]
            test: u16,
        }

        let tb = TestBufferThingThree::new_buffer([5, 0]);
        assert_eq!(tb.get_test(), 5);
    }
}