#constraints #api #length #traits #type #api-validation #type-pinned

len_constraints

在您的API中实现类型固定长度约束的特性和类型

3个版本

0.1.2 2019年5月15日
0.1.1 2019年5月3日
0.1.0 2019年4月30日

#2163 in Rust模式

BSD-2-Clause OR MIT

24KB
348

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

len_constraints

欢迎来到 len_constraints 🎉

关于

这个crate实现了特性和类型,允许您在API中实现类型固定长度约束。

为什么?

您见过多少这样的API?

// BAD EXAMPLE!

fn encrypt(buf: &mut[u8], plaintext: &[u8], key: &[u8], nonce: &[u8])
	-> Result<usize, Box<dyn Error + 'static>>
{
	// 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!()
}

如您所见,这个API相当不透明,需要大量的手动检查。

当然,有人可能使用数组引用

// MEH EXAMPLE...

fn encrypt(buf: &mut[u8], plaintext: &[u8], key: &[u8; 32], nonce: &[u8; 12])
	-> Result<usize, Box<dyn Error + 'static>>
{
	// 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!()
}

但数组引用也有其缺点。它们不适用于多个有效长度(允许在16..=32中任何东西)也不能表示相对关系。此外,将其他数据类型和数组之间进行转换可能会很烦人。

len_constraints试图解决这个问题

// GOOD EXAMPLE :D

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

fn encrypt(buf: RelativeMut<u8, Add, _16>, plaintext: Ranged<u8, _0, _65536>,
	key: Fixed<u8, _32>, nonce: Fixed<u8, _12>) -> Result<usize, Box<Error + 'static>>
{
	// Get buffer (we do this here because there may not be a relationship at an earlier stage)
	let buf = buf.get_slice_mut(plaintext.len())?;

	// Do sth.
	Ok(7)
}

fn main() -> Result<(), Box<Error + 'static>> {
	// 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(())
}

如您所见,我们现在可以在函数签名中描述复杂的关系——这使得API更加透明,并消除了手动(且容易出错的)参数验证的需要。此外,API也适合切片。

无运行时依赖