#![no_std]
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
#![doc = include_str!("../README.md")]
#![warn(
clippy::mod_module_files,
clippy::unwrap_used,
rust_2018_idioms,
unused_lifetimes
)]
#[macro_use]
extern crate alloc;
#[cfg(feature = "std")]
extern crate std;
use alloc::{string::String, vec::Vec};
use core::fmt::{self, Display};
#[cfg(feature = "std")]
use std::io::{Read, Write};
mod arrays;
mod primitives;
mod quic_vec;
mod tls_vec;
pub use tls_vec::{
SecretTlsVecU16, SecretTlsVecU24, SecretTlsVecU32, SecretTlsVecU8, TlsByteSliceU16,
TlsByteSliceU24, TlsByteSliceU32, TlsByteSliceU8, TlsByteVecU16, TlsByteVecU24, TlsByteVecU32,
TlsByteVecU8, TlsSliceU16, TlsSliceU24, TlsSliceU32, TlsSliceU8, TlsVecU16, TlsVecU24,
TlsVecU32, TlsVecU8,
};
#[cfg(feature = "std")]
pub use quic_vec::SecretVLBytes;
pub use quic_vec::{VLByteSlice, VLBytes};
#[cfg(feature = "derive")]
pub use tls_codec_derive::{
TlsDeserialize, TlsDeserializeBytes, TlsSerialize, TlsSerializeBytes, TlsSize,
};
#[cfg(feature = "conditional_deserialization")]
pub use tls_codec_derive::conditionally_deserializable;
#[derive(Debug, Eq, PartialEq, Clone)]
pub enum Error {
EncodingError(String),
InvalidVectorLength,
InvalidWriteLength(String),
InvalidInput,
DecodingError(String),
EndOfStream,
TrailingData,
UnknownValue(u64),
LibraryError,
}
#[cfg(feature = "std")]
impl std::error::Error for Error {}
impl Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_fmt(format_args!("{self:?}"))
}
}
#[cfg(feature = "std")]
impl From<std::io::Error> for Error {
fn from(e: std::io::Error) -> Self {
match e.kind() {
std::io::ErrorKind::UnexpectedEof => Self::EndOfStream,
_ => Self::DecodingError(format!("io error: {e:?}")),
}
}
}
pub trait Size {
fn tls_serialized_len(&self) -> usize;
}
pub trait Serialize: Size {
#[cfg(feature = "std")]
fn tls_serialize<W: Write>(&self, writer: &mut W) -> Result<usize, Error>;
#[cfg(feature = "std")]
fn tls_serialize_detached(&self) -> Result<Vec<u8>, Error> {
let mut buffer = Vec::with_capacity(self.tls_serialized_len());
let written = self.tls_serialize(&mut buffer)?;
debug_assert_eq!(
written,
buffer.len(),
"Expected that {} bytes were written but the output holds {} bytes",
written,
buffer.len()
);
if written != buffer.len() {
Err(Error::EncodingError(format!(
"Expected that {} bytes were written but the output holds {} bytes",
written,
buffer.len()
)))
} else {
Ok(buffer)
}
}
}
pub trait SerializeBytes: Size {
fn tls_serialize(&self) -> Result<Vec<u8>, Error>;
}
pub trait Deserialize: Size {
#[cfg(feature = "std")]
fn tls_deserialize<R: Read>(bytes: &mut R) -> Result<Self, Error>
where
Self: Sized;
#[cfg(feature = "std")]
fn tls_deserialize_exact(bytes: impl AsRef<[u8]>) -> Result<Self, Error>
where
Self: Sized,
{
let mut bytes = bytes.as_ref();
let out = Self::tls_deserialize(&mut bytes)?;
if !bytes.is_empty() {
return Err(Error::TrailingData);
}
Ok(out)
}
}
pub trait DeserializeBytes: Size {
fn tls_deserialize_bytes(bytes: &[u8]) -> Result<(Self, &[u8]), Error>
where
Self: Sized;
fn tls_deserialize_exact_bytes(bytes: &[u8]) -> Result<Self, Error>
where
Self: Sized,
{
let (out, remainder) = Self::tls_deserialize_bytes(bytes)?;
if !remainder.is_empty() {
return Err(Error::TrailingData);
}
Ok(out)
}
}
#[derive(Copy, Clone, Debug, Default, PartialEq)]
pub struct U24([u8; 3]);
impl U24 {
pub const MAX: Self = Self([255u8; 3]);
pub const MIN: Self = Self([0u8; 3]);
pub fn from_be_bytes(bytes: [u8; 3]) -> Self {
U24(bytes)
}
pub fn to_be_bytes(self) -> [u8; 3] {
self.0
}
}
impl From<U24> for usize {
fn from(value: U24) -> usize {
const LEN: usize = core::mem::size_of::<usize>();
let mut usize_bytes = [0u8; LEN];
usize_bytes[LEN - 3..].copy_from_slice(&value.0);
usize::from_be_bytes(usize_bytes)
}
}
impl TryFrom<usize> for U24 {
type Error = Error;
fn try_from(value: usize) -> Result<Self, Self::Error> {
const LEN: usize = core::mem::size_of::<usize>();
if value > (1 << 24) - 1 {
Err(Error::LibraryError)
} else {
Ok(U24(value.to_be_bytes()[LEN - 3..].try_into()?))
}
}
}