#![doc(
html_logo_url = "https://commonware.xyz/imgs/rustdoc_logo.svg",
html_favicon_url = "https://commonware.xyz/favicon.ico"
)]
#![cfg_attr(not(any(feature = "std", test)), no_std)]
commonware_macros::stability_scope!(ALPHA, cfg(feature = "std") {
pub mod rng;
pub use rng::{test_rng, test_rng_seeded, FuzzRng};
pub mod thread_local;
pub use thread_local::Cached;
});
commonware_macros::stability_scope!(BETA {
#[cfg(not(feature = "std"))]
extern crate alloc;
#[cfg(not(feature = "std"))]
use alloc::{boxed::Box, string::String, vec::Vec};
use bytes::{BufMut, BytesMut};
use core::{fmt::Write as FmtWrite, time::Duration};
pub mod faults;
pub use faults::{Faults, N3f1, N5f1};
pub mod sequence;
pub use sequence::{Array, Span};
pub mod hostname;
pub use hostname::Hostname;
pub mod bitmap;
pub mod ordered;
use bytes::Buf;
use commonware_codec::{varint::UInt, EncodeSize, Error as CodecError, Read, ReadExt, Write};
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub struct Participant(u32);
impl Participant {
pub const fn new(index: u32) -> Self {
Self(index)
}
pub fn from_usize(index: usize) -> Self {
Self(u32::try_from(index).expect("participant index exceeds u32::MAX"))
}
pub const fn get(self) -> u32 {
self.0
}
}
impl From<Participant> for usize {
fn from(p: Participant) -> Self {
p.0 as Self
}
}
impl core::fmt::Display for Participant {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "{}", self.0)
}
}
impl Read for Participant {
type Cfg = ();
fn read_cfg(buf: &mut impl Buf, _cfg: &Self::Cfg) -> Result<Self, CodecError> {
let value: u32 = UInt::read(buf)?.into();
Ok(Self(value))
}
}
impl Write for Participant {
fn write(&self, buf: &mut impl bytes::BufMut) {
UInt(self.0).write(buf);
}
}
impl EncodeSize for Participant {
fn encode_size(&self) -> usize {
UInt(self.0).encode_size()
}
}
pub trait TryFromIterator<T>: Sized {
type Error;
fn try_from_iter<I: IntoIterator<Item = T>>(iter: I) -> Result<Self, Self::Error>;
}
pub trait TryCollect: Iterator + Sized {
fn try_collect<C: TryFromIterator<Self::Item>>(self) -> Result<C, C::Error> {
C::try_from_iter(self)
}
}
impl<I: Iterator> TryCollect for I {}
pub type BoxedError = Box<dyn core::error::Error + Send + Sync>;
pub fn hex(bytes: &[u8]) -> String {
let mut hex = String::with_capacity(bytes.len() * 2);
for byte in bytes.iter() {
write!(hex, "{byte:02x}").expect("writing to string should never fail");
}
hex
}
pub fn from_hex(hex: &str) -> Option<Vec<u8>> {
let bytes = hex.as_bytes();
if !bytes.len().is_multiple_of(2) {
return None;
}
bytes
.chunks_exact(2)
.map(|chunk| {
let hi = decode_hex_digit(chunk[0])?;
let lo = decode_hex_digit(chunk[1])?;
Some((hi << 4) | lo)
})
.collect()
}
pub fn from_hex_formatted(hex: &str) -> Option<Vec<u8>> {
let hex = hex.replace(['\t', '\n', '\r', ' '], "");
let res = hex.strip_prefix("0x").unwrap_or(&hex);
from_hex(res)
}
pub fn union(a: &[u8], b: &[u8]) -> Vec<u8> {
let mut union = Vec::with_capacity(a.len() + b.len());
union.extend_from_slice(a);
union.extend_from_slice(b);
union
}
pub fn union_unique(namespace: &[u8], msg: &[u8]) -> Vec<u8> {
use commonware_codec::EncodeSize;
let len_prefix = namespace.len();
let mut buf =
BytesMut::with_capacity(len_prefix.encode_size() + namespace.len() + msg.len());
len_prefix.write(&mut buf);
BufMut::put_slice(&mut buf, namespace);
BufMut::put_slice(&mut buf, msg);
buf.into()
}
pub fn modulo(bytes: &[u8], n: u64) -> u64 {
assert_ne!(n, 0, "modulus must be non-zero");
let n = n as u128;
let mut result = 0u128;
for &byte in bytes {
result = (result << 8) | (byte as u128);
result %= n;
}
result as u64
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct NonZeroDuration(Duration);
impl NonZeroDuration {
pub fn new(duration: Duration) -> Option<Self> {
if duration == Duration::ZERO {
None
} else {
Some(Self(duration))
}
}
pub fn new_panic(duration: Duration) -> Self {
Self::new(duration).expect("duration must be non-zero")
}
pub const fn get(self) -> Duration {
self.0
}
}
impl From<NonZeroDuration> for Duration {
fn from(nz_duration: NonZeroDuration) -> Self {
nz_duration.0
}
}
});
commonware_macros::stability_scope!(BETA, cfg(feature = "std") {
pub mod acknowledgement;
pub use acknowledgement::Acknowledgement;
pub mod net;
pub use net::IpAddrExt;
pub mod time;
pub use time::{DurationExt, SystemTimeExt};
pub mod rational;
pub use rational::BigRationalExt;
mod priority_set;
pub use priority_set::PrioritySet;
pub mod channel;
pub mod concurrency;
pub mod futures;
pub mod sync;
});
#[cfg(not(any(
commonware_stability_GAMMA,
commonware_stability_DELTA,
commonware_stability_EPSILON,
commonware_stability_RESERVED
)))] pub mod hex_literal;
#[cfg(not(any(
commonware_stability_GAMMA,
commonware_stability_DELTA,
commonware_stability_EPSILON,
commonware_stability_RESERVED
)))] pub mod vec;
#[commonware_macros::stability(BETA)]
#[inline]
const fn decode_hex_digit(byte: u8) -> Option<u8> {
match byte {
b'0'..=b'9' => Some(byte - b'0'),
b'a'..=b'f' => Some(byte - b'a' + 10),
b'A'..=b'F' => Some(byte - b'A' + 10),
_ => None,
}
}
#[macro_export]
macro_rules! NZUsize {
($val:literal) => {
const { ::core::num::NonZeroUsize::new($val).expect("value must be non-zero") }
};
($val:expr) => {
::core::num::NonZeroUsize::new($val).expect("value must be non-zero")
};
}
#[macro_export]
macro_rules! NZU8 {
($val:literal) => {
const { ::core::num::NonZeroU8::new($val).expect("value must be non-zero") }
};
($val:expr) => {
::core::num::NonZeroU8::new($val).expect("value must be non-zero")
};
}
#[macro_export]
macro_rules! NZU16 {
($val:literal) => {
const { ::core::num::NonZeroU16::new($val).expect("value must be non-zero") }
};
($val:expr) => {
::core::num::NonZeroU16::new($val).expect("value must be non-zero")
};
}
#[macro_export]
macro_rules! NZU32 {
($val:literal) => {
const { ::core::num::NonZeroU32::new($val).expect("value must be non-zero") }
};
($val:expr) => {
::core::num::NonZeroU32::new($val).expect("value must be non-zero")
};
}
#[macro_export]
macro_rules! NZU64 {
($val:literal) => {
const { ::core::num::NonZeroU64::new($val).expect("value must be non-zero") }
};
($val:expr) => {
::core::num::NonZeroU64::new($val).expect("value must be non-zero")
};
}
#[macro_export]
macro_rules! NZDuration {
($val:expr) => {
$crate::NonZeroDuration::new_panic($val)
};
}
#[cfg(test)]
mod tests {
use super::*;
use num_bigint::BigUint;
use rand::{rngs::StdRng, Rng, SeedableRng};
#[test]
fn test_hex() {
let b = &[];
let h = hex(b);
assert_eq!(h, "");
assert_eq!(from_hex(&h).unwrap(), b.to_vec());
let b = &hex!("0x01");
let h = hex(b);
assert_eq!(h, "01");
assert_eq!(from_hex(&h).unwrap(), b.to_vec());
let b = &hex!("0x010203");
let h = hex(b);
assert_eq!(h, "010203");
assert_eq!(from_hex(&h).unwrap(), b.to_vec());
let h = "0102030";
assert!(from_hex(h).is_none());
let h = "01g3";
assert!(from_hex(h).is_none());
let h = "+123";
assert!(from_hex(h).is_none());
assert_eq!(from_hex(""), Some(vec![]));
}
#[test]
fn test_from_hex_formatted() {
let b = &[];
let h = hex(b);
assert_eq!(h, "");
assert_eq!(from_hex_formatted(&h).unwrap(), b.to_vec());
let b = &hex!("0x01");
let h = hex(b);
assert_eq!(h, "01");
assert_eq!(from_hex_formatted(&h).unwrap(), b.to_vec());
let b = &hex!("0x010203");
let h = hex(b);
assert_eq!(h, "010203");
assert_eq!(from_hex_formatted(&h).unwrap(), b.to_vec());
let h = "0102030";
assert!(from_hex_formatted(h).is_none());
let h = "01g3";
assert!(from_hex_formatted(h).is_none());
let h = "01 02 03";
assert_eq!(from_hex_formatted(h).unwrap(), b.to_vec());
let h = "0x010203";
assert_eq!(from_hex_formatted(h).unwrap(), b.to_vec());
let h = " \n\n0x\r\n01
02\t03\n";
assert_eq!(from_hex_formatted(h).unwrap(), b.to_vec());
}
#[test]
fn test_from_hex_utf8_char_boundaries() {
const MISALIGNMENT_CASE: &str = "쀘\n";
let b = from_hex(MISALIGNMENT_CASE);
assert!(b.is_none());
}
#[test]
fn test_union() {
assert_eq!(union(&[], &[]), Vec::<u8>::new());
assert_eq!(union(&[], &hex!("0x010203")), hex!("0x010203"));
assert_eq!(
union(&hex!("0x010203"), &hex!("0x040506")),
hex!("0x010203040506")
);
}
#[test]
fn test_union_unique() {
let namespace = b"namespace";
let msg = b"message";
let length_encoding = vec![0b0000_1001];
let mut expected = Vec::with_capacity(length_encoding.len() + namespace.len() + msg.len());
expected.extend_from_slice(&length_encoding);
expected.extend_from_slice(namespace);
expected.extend_from_slice(msg);
let result = union_unique(namespace, msg);
assert_eq!(result, expected);
assert_eq!(result.len(), result.capacity());
}
#[test]
fn test_union_unique_zero_length() {
let namespace = b"";
let msg = b"message";
let length_encoding = vec![0];
let mut expected = Vec::with_capacity(length_encoding.len() + namespace.len() + msg.len());
expected.extend_from_slice(&length_encoding);
expected.extend_from_slice(msg);
let result = union_unique(namespace, msg);
assert_eq!(result, expected);
assert_eq!(result.len(), result.capacity());
}
#[test]
fn test_union_unique_long_length() {
let namespace = &b"n".repeat(256);
let msg = b"message";
let length_encoding = vec![0b1000_0000, 0b0000_0010];
let mut expected = Vec::with_capacity(length_encoding.len() + namespace.len() + msg.len());
expected.extend_from_slice(&length_encoding);
expected.extend_from_slice(namespace);
expected.extend_from_slice(msg);
let result = union_unique(namespace, msg);
assert_eq!(result, expected);
assert_eq!(result.len(), result.capacity());
}
#[test]
fn test_modulo() {
assert_eq!(modulo(&[], 1), 0);
assert_eq!(modulo(&hex!("0x01"), 1), 0);
assert_eq!(modulo(&hex!("0x010203"), 10), 1);
for i in 0..100 {
let mut rng = StdRng::seed_from_u64(i);
let bytes: [u8; 32] = rng.gen();
let n = 11u64;
let big_modulo = BigUint::from_bytes_be(&bytes) % n;
let utils_modulo = modulo(&bytes, n);
assert_eq!(big_modulo, BigUint::from(utils_modulo));
let n = 11_111u64;
let big_modulo = BigUint::from_bytes_be(&bytes) % n;
let utils_modulo = modulo(&bytes, n);
assert_eq!(big_modulo, BigUint::from(utils_modulo));
let n = 0xDFFFFFFFFFFFFFFD;
let big_modulo = BigUint::from_bytes_be(&bytes) % n;
let utils_modulo = modulo(&bytes, n);
assert_eq!(big_modulo, BigUint::from(utils_modulo));
}
}
#[test]
#[should_panic]
fn test_modulo_zero_panics() {
modulo(&hex!("0x010203"), 0);
}
#[test]
fn test_non_zero_macros_compile_time() {
assert_eq!(NZUsize!(1).get(), 1);
assert_eq!(NZU8!(2).get(), 2);
assert_eq!(NZU16!(3).get(), 3);
assert_eq!(NZU32!(4).get(), 4);
assert_eq!(NZU64!(5).get(), 5);
const _: core::num::NonZeroUsize = NZUsize!(1);
const _: core::num::NonZeroU8 = NZU8!(2);
const _: core::num::NonZeroU16 = NZU16!(3);
const _: core::num::NonZeroU32 = NZU32!(4);
const _: core::num::NonZeroU64 = NZU64!(5);
}
#[test]
fn test_non_zero_macros_runtime() {
let one_usize: usize = 1;
let two_u8: u8 = 2;
let three_u16: u16 = 3;
let four_u32: u32 = 4;
let five_u64: u64 = 5;
assert_eq!(NZUsize!(one_usize).get(), 1);
assert_eq!(NZU8!(two_u8).get(), 2);
assert_eq!(NZU16!(three_u16).get(), 3);
assert_eq!(NZU32!(four_u32).get(), 4);
assert_eq!(NZU64!(five_u64).get(), 5);
let zero_usize: usize = 0;
let zero_u8: u8 = 0;
let zero_u16: u16 = 0;
let zero_u32: u32 = 0;
let zero_u64: u64 = 0;
assert!(std::panic::catch_unwind(|| NZUsize!(zero_usize)).is_err());
assert!(std::panic::catch_unwind(|| NZU8!(zero_u8)).is_err());
assert!(std::panic::catch_unwind(|| NZU16!(zero_u16)).is_err());
assert!(std::panic::catch_unwind(|| NZU32!(zero_u32)).is_err());
assert!(std::panic::catch_unwind(|| NZU64!(zero_u64)).is_err());
assert!(std::panic::catch_unwind(|| NZDuration!(Duration::ZERO)).is_err());
assert_eq!(
NZDuration!(Duration::from_secs(1)).get(),
Duration::from_secs(1)
);
}
#[test]
fn test_non_zero_duration() {
assert!(NonZeroDuration::new(Duration::ZERO).is_none());
let duration = Duration::from_millis(100);
let nz_duration = NonZeroDuration::new(duration).unwrap();
assert_eq!(nz_duration.get(), duration);
assert_eq!(Duration::from(nz_duration), duration);
assert!(std::panic::catch_unwind(|| NonZeroDuration::new_panic(Duration::ZERO)).is_err());
let d1 = NonZeroDuration::new(Duration::from_millis(100)).unwrap();
let d2 = NonZeroDuration::new(Duration::from_millis(200)).unwrap();
assert!(d1 < d2);
}
#[test]
fn test_participant_constructors() {
assert_eq!(Participant::new(0).get(), 0);
assert_eq!(Participant::new(42).get(), 42);
assert_eq!(Participant::from_usize(0).get(), 0);
assert_eq!(Participant::from_usize(42).get(), 42);
assert_eq!(Participant::from_usize(u32::MAX as usize).get(), u32::MAX);
}
#[test]
#[should_panic(expected = "participant index exceeds u32::MAX")]
fn test_participant_from_usize_overflow() {
Participant::from_usize((u32::MAX as usize) + 1);
}
#[test]
fn test_participant_display() {
assert_eq!(format!("{}", Participant::new(0)), "0");
assert_eq!(format!("{}", Participant::new(42)), "42");
assert_eq!(format!("{}", Participant::new(1000)), "1000");
}
#[test]
fn test_participant_ordering() {
assert!(Participant::new(0) < Participant::new(1));
assert!(Participant::new(5) < Participant::new(10));
assert!(Participant::new(10) > Participant::new(5));
assert_eq!(Participant::new(42), Participant::new(42));
}
#[test]
fn test_participant_encode_decode() {
use commonware_codec::{DecodeExt, Encode};
let cases = vec![0u32, 1, 127, 128, 255, 256, u32::MAX];
for value in cases {
let participant = Participant::new(value);
let encoded = participant.encode();
assert_eq!(encoded.len(), participant.encode_size());
let decoded = Participant::decode(encoded).unwrap();
assert_eq!(participant, decoded);
}
}
#[cfg(feature = "arbitrary")]
mod conformance {
use super::*;
use commonware_codec::conformance::CodecConformance;
commonware_conformance::conformance_tests! {
CodecConformance<Participant>,
}
}
}