#![no_std]
#![cfg_attr(docsrs, feature(doc_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 string;
mod tls_vec;
mod varint;
pub use tls_vec::{
SecretTlsVecU8, SecretTlsVecU16, SecretTlsVecU24, SecretTlsVecU32, TlsByteSliceU8,
TlsByteSliceU16, TlsByteSliceU24, TlsByteSliceU32, TlsByteVecU8, TlsByteVecU16, TlsByteVecU24,
TlsByteVecU32, TlsSliceU8, TlsSliceU16, TlsSliceU24, TlsSliceU32, TlsVecU8, TlsVecU16,
TlsVecU24, TlsVecU32,
};
#[cfg(feature = "std")]
#[cfg_attr(feature = "future_deprecations", allow(deprecated))]
pub use quic_vec::SecretVLBytes;
#[cfg_attr(feature = "future_deprecations", allow(deprecated))]
pub use quic_vec::VLBytes;
#[cfg(feature = "std")]
pub use quic_vec::{SecretVLByteVec, rw as vlen};
pub use quic_vec::{VLByteSlice, VLByteVec};
#[cfg(feature = "derive")]
pub use tls_codec_derive::{
TlsDeserialize, TlsDeserializeBytes, TlsSerialize, TlsSerializeBytes, TlsSize,
};
#[cfg(feature = "conditional_deserialization")]
pub use tls_codec_derive::conditionally_deserializable;
pub use varint::TlsVarInt;
#[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:?}")),
}
}
}
#[cfg(any(feature = "std", feature = "serde"))]
pub(crate) const MAX_PREALLOC: usize = 4096;
#[cfg(feature = "std")]
fn read_bytes_bounded<R: std::io::Read>(reader: &mut R, len: usize) -> Result<Vec<u8>, Error> {
if len > isize::MAX as usize {
return Err(Error::InvalidVectorLength);
}
let mut result = Vec::with_capacity(core::cmp::min(len, MAX_PREALLOC));
reader.take(len as u64).read_to_end(&mut result)?;
if result.len() != len {
return Err(Error::EndOfStream);
}
Ok(result)
}
#[inline(always)]
#[cfg(target_pointer_width = "64")]
pub(crate) const fn len_add(a: usize, b: usize) -> usize {
a + b
}
#[inline(always)]
#[cfg(not(target_pointer_width = "64"))]
pub(crate) const fn len_add(a: usize, b: usize) -> usize {
a.saturating_add(b)
}
#[inline(always)]
#[cfg(target_pointer_width = "64")]
pub(crate) fn checked_len_add(a: usize, b: usize) -> Result<usize, Error> {
Ok(a + b)
}
#[inline(always)]
#[cfg(not(target_pointer_width = "64"))]
pub(crate) fn checked_len_add(a: usize, b: usize) -> Result<usize, Error> {
a.checked_add(b).ok_or(Error::InvalidVectorLength)
}
#[inline(always)]
pub(crate) fn checked_capacity(len: usize) -> Result<usize, Error> {
if len > isize::MAX as usize {
return Err(Error::InvalidVectorLength);
}
Ok(len)
}
#[inline(always)]
pub(crate) fn checked_alloc_len(a: usize, b: usize) -> Result<usize, Error> {
checked_capacity(a.saturating_add(b))
}
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(checked_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_bytes(&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()?))
}
}
}