il2-utils 0.1.2

InterlockLedger's utility library in Rust.
Documentation
/*
 * BSD 3-Clause License
 *
 * Copyright (c) 2019-2020, InterlockLedger Network
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * * Redistributions of source code must retain the above copyright notice, this
 *   list of conditions and the following disclaimer.
 *
 * * Redistributions in binary form must reproduce the above copyright notice,
 *   this list of conditions and the following disclaimer in the documentation
 *   and/or other materials provided with the distribution.
 *
 * * Neither the name of the copyright holder nor the names of its
 *   contributors may be used to endorse or promote products derived from
 *   this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
//=============================================================================
//! This module implements a simple data serializer/deserialzer that can be
//! used to read/write data serializations in memory. Most of the functions
//! here where designed to use pre-allocated memory segments and/or vectors
//! in place. As such, this module is not recommended for complex
//! serializations or large values.
//!
//! If you want to use the operation `?` to remap the errors form this just
//! implement the trait [`std::convert::From`] to convert [`ErrorKind`] into
//! your own error type.
#[cfg(test)]
mod tests;

/// Errors generated by this
#[derive(Debug)]
pub enum ErrorKind {
    UnableToRead,
    UnableToWrite,
}

pub type Result<T> = std::result::Result<T, ErrorKind>;

//=============================================================================
// SimpleDataSerializer
//-----------------------------------------------------------------------------
/// This trait implements a simple serializer for basic data types.
/// It follows the format used by Java's `java.io.DataOutputStream` and write
/// all values using the big endian format.
///
/// This trait also allows the definition of a custom Result type thar will
/// allow its methods to be used with the operatior `?`.
pub trait SimpleDataSerializer {
    /// Writes the byte slice.
    ///
    /// Arguments:
    /// - `v`: The value to write;
    fn write(&mut self, v: &[u8]) -> Result<()>;

    /// Writes an u8 value.
    ///
    /// Arguments:
    /// - `v`: The value to write;
    fn write_u8(&mut self, v: u8) -> Result<()>;

    /// Writes an u16 value.
    ///
    /// Arguments:
    /// - `v`: The value to write;
    fn write_u16(&mut self, v: u16) -> Result<()> {
        self.write(&v.to_be_bytes())
    }

    /// Writes an u32 value.
    ///
    /// Arguments:
    /// - `v`: The value to write;
    fn write_u32(&mut self, v: u32) -> Result<()> {
        self.write(&v.to_be_bytes())
    }

    /// Writes an u64 value.
    ///
    /// Arguments:
    /// - `v`: The value to write;
    fn write_u64(&mut self, v: u64) -> Result<()> {
        self.write(&v.to_be_bytes())
    }

    /// Writes an i8 value.
    ///
    /// Arguments:
    /// - `v`: The value to write;
    fn write_i8(&mut self, v: i8) -> Result<()> {
        self.write_u8(v as u8)
    }

    /// Writes an i16 value.
    ///
    /// Arguments:
    /// - `v`: The value to write;
    fn write_i16(&mut self, v: i16) -> Result<()> {
        self.write_u16(v as u16)
    }

    /// Writes an i32 value.
    ///
    /// Arguments:
    /// - `v`: The value to write;

    fn write_i32(&mut self, v: i32) -> Result<()> {
        self.write_u32(v as u32)
    }

    /// Writes an i64 value.
    ///
    /// Arguments:
    /// - `v`: The value to write;
    fn write_i64(&mut self, v: i64) -> Result<()> {
        self.write_u64(v as u64)
    }

    /// Writes a f32 value.
    ///
    /// Arguments:
    /// - `v`: The value to write;
    fn write_f32(&mut self, v: f32) -> Result<()> {
        self.write(&v.to_be_bytes())
    }

    /// Writes a f64 value.
    ///
    /// Arguments:
    /// - `v`: The value to write;
    fn write_f64(&mut self, v: f64) -> Result<()> {
        self.write(&v.to_be_bytes())
    }

    /// Writes a byte array. The size of the byte array is encoded
    /// as an u16 value followed by the bytes of the array.
    ///
    /// Arguments:
    /// - `v`: The value to write;
    fn write_byte_array(&mut self, v: &[u8]) -> Result<()> {
        self.write_u16(v.len() as u16)?;
        self.write(v)
    }
}

//=============================================================================
// SimpleDataDeserializer
//-----------------------------------------------------------------------------
macro_rules! simpledatadeserializer_read_impl {
    ($type: ty, $func_name:ident, $doc: expr) => {
        #[doc = $doc]
        fn $func_name(&mut self) -> Result<$type> {
            const DATA_SIZE: usize = std::mem::size_of::<$type>();
            self.read(DATA_SIZE)?;
            let mut tmp: [u8; DATA_SIZE] = [0; DATA_SIZE];
            tmp.copy_from_slice(self.data());
            Ok(<$type>::from_be_bytes(tmp))
        }
    };
}

/// This trait implements a simple deserializer for basic data types.
/// It follows the format used by Java's `java.io.DataOutputStream` so it
/// reads the values using the big endian format.
///
/// This trait also allows the definition of a custom Result type thar will
/// allow its methods to be used with the operatior `?`.
pub trait SimpleDataDeserializer {
    /// The slice with the last data read.
    fn data(&self) -> &[u8];

    /// Reads the specified umber of bytes. The data read will available
    /// by [`Self::data()`].
    ///
    /// Arguments:
    /// - `size`: Number of bytes to read;
    fn read(&mut self, size: usize) -> Result<()>;

    /// Reads an u8 value.
    fn read_u8(&mut self) -> Result<u8> {
        self.read(1)?;
        Ok(self.data()[0])
    }

    /// Reads an i8 value.
    fn read_i8(&mut self) -> Result<i8> {
        Ok(self.read_u8()? as i8)
    }

    simpledatadeserializer_read_impl!(u16, read_u16, "Reads an u16 value.");
    simpledatadeserializer_read_impl!(u32, read_u32, "Reads an u32 value.");
    simpledatadeserializer_read_impl!(u64, read_u64, "Reads an u16 value.");
    simpledatadeserializer_read_impl!(i16, read_i16, "Reads an i16 value.");
    simpledatadeserializer_read_impl!(i32, read_i32, "Reads an i32 value.");
    simpledatadeserializer_read_impl!(i64, read_i64, "Reads an i64 value.");
    simpledatadeserializer_read_impl!(f32, read_f32, "Reads an f32 value.");
    simpledatadeserializer_read_impl!(f64, read_f64, "Reads an f64 value.");

    /// Writes a byte array. The size of the byte array is encoded
    /// as an u16 value followed by the bytes of the array.
    ///
    /// Arguments:
    /// - `v`: The value to write;
    fn read_byte_array(&mut self) -> Result<()> {
        let size = self.read_u16()? as usize;
        self.read(size)
    }
}

impl SimpleDataSerializer for Vec<u8> {
    fn write(&mut self, v: &[u8]) -> Result<()> {
        self.extend_from_slice(v);
        Ok(())
    }

    fn write_u8(&mut self, v: u8) -> Result<()> {
        self.push(v);
        Ok(())
    }
}

//=============================================================================
// SimpleSliceSerializer
//-----------------------------------------------------------------------------
/// This struct implements a simple serializer that writes data into a borrowed
/// byte slice.
pub struct SimpleSliceSerializer<'a> {
    slice: &'a mut [u8],
    offset: usize,
}

impl<'a> SimpleSliceSerializer<'a> {
    /// Creates a new instance with a given initial capacity.
    pub fn new(slice: &'a mut [u8]) -> Self {
        Self { slice, offset: 0 }
    }

    /// Returns the current offset.
    pub fn offset(&self) -> usize {
        self.offset
    }

    /// Returns the number of available bytes.
    pub fn available(&self) -> usize {
        self.slice.len() - self.offset
    }

    fn can_write(&self, size: usize) -> Result<()> {
        if size <= self.available() {
            Ok(())
        } else {
            Err(ErrorKind::UnableToWrite)
        }
    }
}

impl<'a> SimpleDataSerializer for SimpleSliceSerializer<'a> {
    fn write(&mut self, v: &[u8]) -> Result<()> {
        self.can_write(v.len())?;
        self.slice[self.offset..self.offset + v.len()].copy_from_slice(v);
        self.offset += v.len();
        Ok(())
    }

    fn write_u8(&mut self, v: u8) -> Result<()> {
        self.can_write(1)?;
        self.slice[self.offset] = v;
        self.offset += 1;
        Ok(())
    }
}

//=============================================================================
// SimpleReader
//-----------------------------------------------------------------------------
/// This struct implements a simple data deserializer. It is the counterpart of
/// the [`SimpleDataSerializer`] trait.
///
/// The template parameter E is the type used to define the type of the error
/// that will compose the results. The actual value of E is defined by the
/// constructor.
pub struct SimpleSliceDeserializer<'a> {
    data: &'a [u8],
    offset: usize,
    data_offset: usize,
}

impl<'a> SimpleSliceDeserializer<'a> {
    /// Creates a new instance that reads data from the slice and returns the
    /// specified value on error.
    pub fn new(data: &'a [u8]) -> Self {
        Self {
            data,
            offset: 0,
            data_offset: 0,
        }
    }

    /// Returns the current offset.
    pub fn offset(&self) -> usize {
        self.offset
    }

    /// Return the number of bytes availble.
    pub fn avaliable(&self) -> usize {
        self.data.len() - self.offset
    }

    /// Returns true if there is no more bytes to read.
    pub fn is_empty(&self) -> bool {
        self.avaliable() == 0
    }

    fn can_read(&self, size: usize) -> Result<()> {
        if size <= self.avaliable() {
            Ok(())
        } else {
            Err(ErrorKind::UnableToRead)
        }
    }
}

impl<'a> SimpleDataDeserializer for SimpleSliceDeserializer<'a> {
    fn data(&self) -> &[u8] {
        &self.data[self.data_offset..self.offset]
    }

    fn read(&mut self, size: usize) -> Result<()> {
        self.can_read(size)?;
        self.data_offset = self.offset;
        self.offset += size;
        Ok(())
    }
}