use crate::err::ValueTooBigError;
#[derive(Copy, Clone, Default, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct Ipv6FlowLabel(u32);
impl Ipv6FlowLabel {
pub const ZERO: Ipv6FlowLabel = Ipv6FlowLabel(0);
pub const MAX_U32: u32 = 0b1111_1111_1111_1111_1111;
#[inline]
pub const fn try_new(value: u32) -> Result<Ipv6FlowLabel, ValueTooBigError<u32>> {
use crate::err::ValueType;
if value <= Ipv6FlowLabel::MAX_U32 {
Ok(Ipv6FlowLabel(value))
} else {
Err(ValueTooBigError {
actual: value,
max_allowed: Ipv6FlowLabel::MAX_U32,
value_type: ValueType::Ipv6FlowLabel,
})
}
}
#[inline]
pub const unsafe fn new_unchecked(value: u32) -> Ipv6FlowLabel {
debug_assert!(value <= Ipv6FlowLabel::MAX_U32);
Ipv6FlowLabel(value)
}
#[inline]
pub const fn value(self) -> u32 {
self.0
}
}
impl core::fmt::Display for Ipv6FlowLabel {
#[inline]
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
self.0.fmt(f)
}
}
impl From<Ipv6FlowLabel> for u32 {
#[inline]
fn from(value: Ipv6FlowLabel) -> Self {
value.0
}
}
impl TryFrom<u32> for Ipv6FlowLabel {
type Error = ValueTooBigError<u32>;
#[inline]
fn try_from(value: u32) -> Result<Self, Self::Error> {
use crate::err::ValueType;
if value <= Ipv6FlowLabel::MAX_U32 {
Ok(Ipv6FlowLabel(value))
} else {
Err(Self::Error {
actual: value,
max_allowed: Ipv6FlowLabel::MAX_U32,
value_type: ValueType::Ipv6FlowLabel,
})
}
}
}
#[cfg(test)]
mod test {
use super::*;
use core::hash::{Hash, Hasher};
use proptest::prelude::*;
use std::format;
#[test]
fn derived_traits() {
{
let a = Ipv6FlowLabel(123);
let b = a;
assert_eq!(a, b);
assert_eq!(a.clone(), a);
}
{
let actual: Ipv6FlowLabel = Default::default();
assert_eq!(actual.value(), 0);
}
{
let a = Ipv6FlowLabel(123);
assert_eq!(format!("{:?}", a), format!("Ipv6FlowLabel(123)"));
}
{
use core::cmp::Ordering;
let a = Ipv6FlowLabel(123);
let b = a;
assert_eq!(a.cmp(&b), Ordering::Equal);
assert_eq!(a.partial_cmp(&b), Some(Ordering::Equal));
}
{
use std::collections::hash_map::DefaultHasher;
let a = {
let mut hasher = DefaultHasher::new();
Ipv6FlowLabel(123).hash(&mut hasher);
hasher.finish()
};
let b = {
let mut hasher = DefaultHasher::new();
Ipv6FlowLabel(123).hash(&mut hasher);
hasher.finish()
};
assert_eq!(a, b);
}
}
proptest! {
#[test]
fn try_new(
valid_value in 0..=0b1111_11111111_11111111u32,
invalid_value in 0b1_0000_00000000_00000000u32..=u32::MAX
) {
use crate::err::{ValueType, ValueTooBigError};
assert_eq!(
valid_value,
Ipv6FlowLabel::try_new(valid_value).unwrap().value()
);
assert_eq!(
Ipv6FlowLabel::try_new(invalid_value).unwrap_err(),
ValueTooBigError{
actual: invalid_value,
max_allowed: 0b1111_11111111_11111111,
value_type: ValueType::Ipv6FlowLabel
}
);
}
}
proptest! {
#[test]
fn try_from(
valid_value in 0..=0b1111_11111111_11111111u32,
invalid_value in 0b1_0000_00000000_00000000u32..=u32::MAX
) {
use crate::err::{ValueType, ValueTooBigError};
{
let actual: Ipv6FlowLabel = valid_value.try_into().unwrap();
assert_eq!(actual.value(), valid_value);
let err: Result<Ipv6FlowLabel, ValueTooBigError<u32>> = invalid_value.try_into();
assert_eq!(
err.unwrap_err(),
ValueTooBigError{
actual: invalid_value,
max_allowed: 0b1111_11111111_11111111,
value_type: ValueType::Ipv6FlowLabel
}
);
}
{
assert_eq!(
Ipv6FlowLabel::try_from(valid_value).unwrap().value(),
valid_value
);
assert_eq!(
Ipv6FlowLabel::try_from(invalid_value).unwrap_err(),
ValueTooBigError{
actual: invalid_value,
max_allowed: 0b1111_11111111_11111111,
value_type: ValueType::Ipv6FlowLabel
}
);
}
}
}
proptest! {
#[test]
fn new_unchecked(valid_value in 0..=0b1111_11111111_11111111u32) {
assert_eq!(
valid_value,
unsafe {
Ipv6FlowLabel::new_unchecked(valid_value).value()
}
);
}
}
proptest! {
#[test]
fn fmt(valid_value in 0..=0b1111_11111111_11111111u32) {
assert_eq!(format!("{}", Ipv6FlowLabel(valid_value)), format!("{}", valid_value));
}
}
proptest! {
#[test]
fn from(valid_value in 0..=0b1111_11111111_11111111u32,) {
let frag_offset = Ipv6FlowLabel::try_new(valid_value).unwrap();
let actual: u32 = frag_offset.into();
assert_eq!(actual, valid_value);
}
}
}