docs.rs License BSD-2-Clause License MIT crates.io Download numbers Travis CI AppVeyor CI dependency status

len_constraints

Welcome to len_constraints 🎉

About

This crate implements traits and types that allows you to implement type-pinned length constraints in your API.

Why?

How often have you seen APIs like this? ```rust // BAD EXAMPLE!

fn encrypt(buf: &mut[u8], plaintext: &[u8], key: &[u8], nonce: &[u8]) -> Result> { // Validate parameters if plaintext.len() > 65_635 { Err("Plaintext is too large")? } if buf.len() < plaintext.len() + 16 { Err("Buffer is smaller than plaintext length")? } if key.len() != 32 { Err("Invalid key size")? } if nonce.len() != 12 { Err("Invalid nonce size")? }

// Do sth.
unimplemented!()

} ``` As you can see, this API is pretty opaque and requires a lot of manual checks.

Of course s.o. could use array references: ```rust // MEH EXAMPLE...

fn encrypt(buf: &mut[u8], plaintext: &[u8], key: &[u8; 32], nonce: &[u8; 12]) -> Result> { // Validate parameters if plaintext.len() > 65_635 { Err("Plaintext is too large")? } if buf.len() < plaintext.len() + 16 { Err("Buffer is smaller than plaintext length")? }

// Do sth.
unimplemented!()

} `` But array references also have their disadvantages. They are not suitable for multiple valid lengths (allow anything in16..=32`) nor can they represent relative relationships. Also converting between other data types and arrays can get annoying.

len_constraints tries to solve this problem: ```rust // GOOD EXAMPLE :D

use std::{ convert::TryInto, error::Error }; use lenconstraints::{ slicemut::RelativeMut, slice::{ Fixed, Ranged }, type_math::{ Add, _0, _12, _16, _32, _65536 } };

fn encrypt(buf: RelativeMut, plaintext: Ranged, key: Fixed, nonce: Fixed) -> Result> { // Get buffer (we do this here because there may not be a relationship at an earlier stage) let buf = buf.getslicemut(plaintext.len())?;

// Do sth.
Ok(7)

}

fn main() -> Result<(), Box> { // Parameters let mut buf: &mut[u8] = &mut[0; 9 + 16]; let plaintext: &[u8] = b"Testolope"; let key: &[u8] = &[0; 32]; let nonce = "12 byte Nonc".as_bytes();

// Call function
encrypt(buf.into(), plaintext.try_into()?, key.try_into()?, nonce.try_into()?)?;
Ok(())

} ``` As you can see, we now can describe complex relationships in the function signature – this makes the API more transparent and removes the need for manual (and error-prone) parameter validation. Also, the API is slice-friendly.