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