1use crate::{Error, Signature};
3use core::{fmt, str};
4
5impl fmt::LowerHex for Signature {
6 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
7 for component in [&self.R, &self.s] {
8 for byte in component {
9 write!(f, "{byte:02x}")?;
10 }
11 }
12 Ok(())
13 }
14}
15
16impl fmt::UpperHex for Signature {
17 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
18 for component in [&self.R, &self.s] {
19 for byte in component {
20 write!(f, "{byte:02X}")?;
21 }
22 }
23 Ok(())
24 }
25}
26
27impl str::FromStr for Signature {
32 type Err = Error;
33
34 fn from_str(hex: &str) -> signature::Result<Self> {
35 if hex.len() != Signature::BYTE_SIZE * 2 {
36 return Err(Error::new());
37 }
38
39 let mut upper_case = None;
40
41 for &byte in hex.as_bytes() {
43 match byte {
44 b'0'..=b'9' => (),
45 b'a'..=b'z' => match upper_case {
46 Some(true) => return Err(Error::new()),
47 Some(false) => (),
48 None => upper_case = Some(false),
49 },
50 b'A'..=b'Z' => match upper_case {
51 Some(true) => (),
52 Some(false) => return Err(Error::new()),
53 None => upper_case = Some(true),
54 },
55 _ => return Err(Error::new()),
56 }
57 }
58
59 let mut result = [0u8; Self::BYTE_SIZE];
60 for (digit, byte) in hex.as_bytes().chunks_exact(2).zip(result.iter_mut()) {
61 *byte = str::from_utf8(digit)
62 .ok()
63 .and_then(|s| u8::from_str_radix(s, 16).ok())
64 .ok_or_else(Error::new)?;
65 }
66
67 Self::try_from(&result[..])
68 }
69}