1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
use core::{convert::TryFrom, fmt, num::NonZeroU64};

use serde::{Deserialize, Deserializer, Serialize};

#[derive(Debug)]
#[allow(clippy::module_name_repetitions)]
pub struct NonZeroOneU64Error(u64);

impl fmt::Display for NonZeroOneU64Error {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        write!(fmt, "{} is zero or one.", self.0)
    }
}

#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, TypeLayout)]
#[repr(transparent)]
#[serde(try_from = "u64", into = "u64")]
pub struct NonZeroOneU64(NonZeroU64);

impl fmt::Display for NonZeroOneU64 {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(&self.0, fmt)
    }
}

impl NonZeroOneU64 {
    /// # Errors
    ///
    /// Returns `NonZeroOneU64Error` if not `1 < value`
    pub const fn new(value: u64) -> Result<Self, NonZeroOneU64Error> {
        match NonZeroU64::new(value) {
            Some(inner) if value > 1 => Ok(Self(inner)),
            _ => Err(NonZeroOneU64Error(value)),
        }
    }

    #[must_use]
    /// Creates a non-zero, non-one u64 without checking the value.
    ///
    /// # Safety
    ///
    /// The value must not be zero or one.
    pub const unsafe fn new_unchecked(value: u64) -> Self {
        Self(NonZeroU64::new_unchecked(value))
    }

    #[must_use]
    pub const fn get(self) -> u64 {
        self.0.get()
    }
}

impl TryFrom<u64> for NonZeroOneU64 {
    type Error = NonZeroOneU64Error;

    fn try_from(value: u64) -> Result<Self, Self::Error> {
        Self::new(value)
    }
}

impl From<NonZeroOneU64> for u64 {
    fn from(val: NonZeroOneU64) -> Self {
        val.get()
    }
}

impl<'de> Deserialize<'de> for NonZeroOneU64 {
    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
        Self::new(u64::deserialize(deserializer)?).map_err(serde::de::Error::custom)
    }
}