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
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
//! Submodule implementing the `TryFrom` trait for the `CAS` number struct.
use std::fmt::Display;
use crate::{CAS, utils::checksum};
impl TryFrom<&str> for CAS {
type Error = crate::errors::Error;
/// Parses a string into a `CAS` number.
///
/// The input string must be in the format `XXXX-XX-X`, where:
/// - `XXXX` is the first part of the CAS number,
/// - `XX` is the second part of the CAS number,
/// - `X` is the check digit.
fn try_from(s: &str) -> Result<Self, Self::Error> {
s.parse()
}
}
impl TryFrom<String> for CAS {
type Error = crate::errors::Error;
/// Parses a string into a `CAS` number.
///
/// The input string must be in the format `XXXX-XX-X`, where:
/// - `XXXX` is the first part of the CAS number,
/// - `XX` is the second part of the CAS number,
/// - `X` is the check digit.
fn try_from(s: String) -> Result<Self, Self::Error> {
s.as_str().try_into()
}
}
impl TryFrom<&String> for CAS {
type Error = crate::errors::Error;
/// Parses a string into a `CAS` number.
///
/// The input string must be in the format `XXXX-XX-X`, where:
/// - `XXXX` is the first part of the CAS number,
/// - `XX` is the second part of the CAS number,
/// - `X` is the check digit.
fn try_from(s: &String) -> Result<Self, Self::Error> {
s.as_str().try_into()
}
}
impl<A, B, C> TryFrom<(A, B, C)> for CAS
where
A: TryInto<u32> + Copy + Display,
B: TryInto<u8> + Copy + Display,
C: TryInto<u8> + Copy + Display,
{
type Error = crate::errors::Error;
/// Parses a tuple into a `CAS` number.
fn try_from(t: (A, B, C)) -> Result<Self, Self::Error> {
let (a, b, c) = t;
let first: u32 = a
.try_into()
.map_err(|_| crate::errors::Error::InvalidString(format!("{a}-{b}-{c}")))?;
let second: u8 = b
.try_into()
.map_err(|_| crate::errors::Error::InvalidString(format!("{a}-{b}-{c}")))?;
let third: u8 = c
.try_into()
.map_err(|_| crate::errors::Error::InvalidString(format!("{a}-{b}-{c}")))?;
let cas = CAS((first * 1000) + (u32::from(second) * 10) + u32::from(third));
let expected = checksum(cas);
if cas.check_digit() != expected {
return Err(crate::errors::Error::InvalidChecksum {
cas: format!("{a}-{b}-{c}"),
expected,
actual: cas.check_digit(),
});
}
Ok(cas)
}
}
impl TryFrom<u32> for CAS {
type Error = crate::errors::Error;
/// Parses a `u32` into a `CAS` number.
fn try_from(value: u32) -> Result<Self, Self::Error> {
let first = value / 1000;
let second = (value % 1000) / 10;
let third = value % 10;
CAS::try_from((first, second, third))
}
}