#![allow(dead_code)]
#![warn(missing_docs)]
pub use uuid::timestamp::context::ContextV1;
use crate::calconfig::{UUIDFactory, UUIDFactoryType};
use crate::uci::{CalError, CalErrorKind, CalResult};
use std::fmt;
use uuid::{Uuid, Variant as UuidVariant, Version as UuidVersion};
pub use crate::asb::{
AbstractReader, AbstractServiceBus, AbstractServiceBusCreateMessage, AbstractServiceBusExt,
AbstractWriter, AsbConnectionState, AsbStatus, AsbStatusListener, Expiration, MessageBuffer,
MessageListener, Reliability, TimeBasedFilter, TopicQos,
};
pub use crate::calconfig::SerializationFormat;
pub use uuid::Timestamp as UuidTimestamp;
#[derive(
Clone, Copy, Default, serde::Deserialize, serde::Serialize, PartialEq, Eq, PartialOrd, Ord, Hash,
)]
pub struct UUID(Uuid);
impl UUID {
fn validate(uuid: Uuid) -> CalResult<Self> {
if uuid.is_nil() {
return Ok(Self(uuid));
}
if uuid.get_variant() != UuidVariant::RFC4122 {
return Err(CalError::new(
CalErrorKind::UuidConformanceError,
format!(
"UUID variant `{:?}` does not satisfy RFC 4122 \
(expected Variant::RFC4122)",
uuid.get_variant()
),
));
}
match uuid.get_version() {
Some(UuidVersion::Mac) | Some(UuidVersion::Md5) | Some(UuidVersion::Random) => Ok(Self(uuid)),
other => Err(CalError::new(
CalErrorKind::UuidConformanceError,
format!(
"UUID version `{:?}` is not permitted; \
OMS allows only v1 (Mac), v3 (Md5), and v4 (Random)",
other
),
)),
}
}
pub fn parse_str(s: &str) -> CalResult<Self> {
let uuid = Uuid::parse_str(s).map_err(|e| {
CalError::new(
CalErrorKind::UuidConformanceError,
format!("UUID parse error: {e}"),
)
})?;
Self::validate(uuid)
}
pub fn from_octets(bytes: [u8; 16]) -> CalResult<Self> {
Self::validate(Uuid::from_bytes(bytes))
}
pub fn try_from_raw(uuid: Uuid) -> CalResult<Self> {
Self::validate(uuid)
}
pub const fn nil() -> Self {
Self(Uuid::nil())
}
pub fn generate(factory: Option<&UUIDFactory>) -> Self {
let def = UUIDFactory::default();
let f = factory.unwrap_or(&def);
match f.type_ {
UUIDFactoryType::Random => Self::generate_v4(),
UUIDFactoryType::TimeBased => {
let ctx = ContextV1::new_random();
let ts = UuidTimestamp::now(&ctx);
if let Some(node) = f.node {
Self::generate_v1(ts, &node.bytes())
} else {
let mac = mac_address::get_mac_address()
.ok()
.flatten()
.unwrap_or(mac_address::MacAddress::new([0; 6]));
Self::generate_v1(ts, &mac.bytes())
}
}
}
}
pub fn generate_v4() -> Self {
Self(Uuid::new_v4())
}
pub fn generate_v1(timestamp: UuidTimestamp, node_id: &[u8; 6]) -> Self {
Self(Uuid::new_v1(timestamp, node_id))
}
pub fn generate_v3(namespace: &UUID, name: &[u8]) -> Self {
Self(Uuid::new_v3(&namespace.0, name))
}
pub fn is_nil(&self) -> bool {
self.0.is_nil()
}
pub fn is_valid(&self) -> bool {
if self.0.is_nil() {
return true;
}
if self.0.get_variant() != UuidVariant::RFC4122 {
return false;
}
matches!(
self.0.get_version(),
Some(UuidVersion::Mac) | Some(UuidVersion::Md5) | Some(UuidVersion::Random)
)
}
pub fn get_variant(&self) -> UuidVariant {
self.0.get_variant()
}
pub fn get_version(&self) -> Option<UuidVersion> {
self.0.get_version()
}
pub fn as_bytes(&self) -> &[u8; 16] {
self.0.as_bytes()
}
pub fn as_raw(&self) -> &Uuid {
&self.0
}
pub fn into_raw(self) -> Uuid {
self.0
}
}
impl fmt::Display for UUID {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(&self.0, f)
}
}
impl fmt::Debug for UUID {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "UUID({})", self.0)
}
}
impl std::str::FromStr for UUID {
type Err = CalError;
fn from_str(s: &str) -> CalResult<Self> {
UUID::parse_str(s)
}
}
impl slog::Value for UUID {
fn serialize(
&self,
record: &slog::Record<'_>,
key: slog::Key,
serializer: &mut dyn slog::Serializer,
) -> slog::Result {
slog::Value::serialize(&self.0, record, key, serializer)
}
}
#[derive(serde::Serialize, serde::Deserialize)]
#[serde(transparent)]
pub struct BoundedList<T>(Vec<T>);
impl<T> BoundedList<T> {
pub const UNBOUNDED_BOUND: usize = usize::MAX;
pub fn new() -> Self {
BoundedList(Vec::new())
}
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
pub fn get_minimum_occurs(&self) -> usize {
0
}
pub fn get_maximum_occurs(&self) -> usize {
Self::UNBOUNDED_BOUND
}
}
impl<T: Default> BoundedList<T> {
pub fn resize(&mut self, new_len: usize) {
self.0.resize_with(new_len, T::default);
}
}
impl<T> std::ops::Deref for BoundedList<T> {
type Target = Vec<T>;
fn deref(&self) -> &Vec<T> {
&self.0
}
}
impl<T> std::ops::DerefMut for BoundedList<T> {
fn deref_mut(&mut self) -> &mut Vec<T> {
&mut self.0
}
}
impl<T: Default> Default for BoundedList<T> {
fn default() -> Self {
BoundedList(Vec::new())
}
}
impl<T: fmt::Debug> fmt::Debug for BoundedList<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(&self.0, f)
}
}
impl<T: Clone> Clone for BoundedList<T> {
fn clone(&self) -> Self {
BoundedList(self.0.clone())
}
}
impl<T: PartialEq> PartialEq for BoundedList<T> {
fn eq(&self, other: &Self) -> bool {
self.0 == other.0
}
}
impl<T> From<Vec<T>> for BoundedList<T> {
fn from(v: Vec<T>) -> Self {
BoundedList(v)
}
}
impl<T> From<BoundedList<T>> for Vec<T> {
fn from(bl: BoundedList<T>) -> Self {
bl.0
}
}
impl<T> IntoIterator for BoundedList<T> {
type Item = T;
type IntoIter = std::vec::IntoIter<T>;
fn into_iter(self) -> Self::IntoIter {
self.0.into_iter()
}
}
impl<'a, T> IntoIterator for &'a BoundedList<T> {
type Item = &'a T;
type IntoIter = std::slice::Iter<'a, T>;
fn into_iter(self) -> Self::IntoIter {
self.0.iter()
}
}
impl<'a, T> IntoIterator for &'a mut BoundedList<T> {
type Item = &'a mut T;
type IntoIter = std::slice::IterMut<'a, T>;
fn into_iter(self) -> Self::IntoIter {
self.0.iter_mut()
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::calconfig::{UUIDFactory, UUIDFactoryType};
use rcal_macros::init_test_logger;
use slog::debug;
#[test]
fn test_bounded_list_resize() {
let mut list = BoundedList::<i32>::new();
list.push(10);
list.push(20);
list.resize(5);
assert_eq!(list.len(), 5);
assert_eq!(list[2], 0);
assert_eq!(list[4], 0);
list.resize(1);
assert_eq!(list.len(), 1);
assert_eq!(list[0], 10);
}
#[init_test_logger]
#[test]
fn test_uuid_factory() {
debug!(logger, "Default (random): {}", UUID::generate(None));
let random_factory = UUIDFactory::default();
debug!(logger, "Change to explicit random");
debug!(logger, "Random: {}", UUID::generate(Some(&random_factory)));
let tb_factory = UUIDFactory {
type_: UUIDFactoryType::TimeBased,
..Default::default()
};
debug!(logger, "Change to time based");
debug!(logger, "TimeBased: {}", UUID::generate(Some(&tb_factory)));
let node = mac_address::get_mac_address()
.expect("test requires a MAC address")
.expect("test requires a MAC address");
debug!(logger, "Time based with local node {}", node);
let tb_node_factory = UUIDFactory {
type_: UUIDFactoryType::TimeBased,
node: Some(node),
..Default::default()
};
debug!(
logger,
"TimeBased: {}",
UUID::generate(Some(&tb_node_factory))
);
}
}