Alioth Code Coverage

net.rs91.89%

1// Copyright 2025 Google LLC
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// https://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use std::str::FromStr;
16
17use serde::Deserialize;
18use serde::de::{self, Visitor};
19use serde_aco::{Help, TypedHelp};
20use zerocopy::{FromBytes, Immutable, IntoBytes};
21
22#[derive(Debug, Clone, Default, FromBytes, Immutable, IntoBytes, PartialEq, Eq)]
23#[repr(transparent)]
24pub struct MacAddr(pub [u8; 6]);
25
26#[derive(Debug)]
27pub enum Error {
28 InvalidLength { len: usize },
29 InvalidNumber { num: String },
30}
31
32impl FromStr for MacAddr {
33 type Err = Error;
34
35 fn from_str(s: &str) -> Result<Self, Self::Err> {19x
36 let mut addr = [0u8; 6];19x
37 let iter = s.split(':');19x
38 let mut index = 0;19x
39 for b_s in iter {114x
40 let Ok(v) = u8::from_str_radix(b_s, 16) else {114x
41 return Err(Error::InvalidNumber {3x
42 num: b_s.to_owned(),3x
43 });3x
44 };
45 if let Some(b) = addr.get_mut(index) {111x
46 *b = v;108x
47 };108x
48 index += 1;111x
49 }
50 if index != 6 {16x
51 return Err(Error::InvalidLength { len: index });6x
52 }10x
53 Ok(MacAddr(addr))10x
54 }19x
55}
56
57impl Help for MacAddr {
58 const HELP: TypedHelp = TypedHelp::Custom { desc: "mac-addr" };
59}
60
61struct MacAddrVisitor;
62
63impl<'de> Visitor<'de> for MacAddrVisitor {
64 type Value = MacAddr;
65
66 fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
67 formatter.write_str("a MAC address like ea:d7:a8:e8:c6:2f")
68 }
69
70 fn visit_borrowed_str<E>(self, v: &'de str) -> Result<Self::Value, E>19x
71 where19x
72 E: de::Error,19x
73 {
74 match v.parse::<MacAddr>() {19x
75 Ok(v) => Ok(v),10x
76 Err(Error::InvalidLength { len }) => Err(E::invalid_length(len, &"6")),6x
77 Err(Error::InvalidNumber { num }) => Err(E::invalid_value(3x
78 de::Unexpected::Str(num.as_str()),3x
79 &"hexadecimal",3x
80 )),3x
81 }
82 }19x
83}
84
85impl<'de> Deserialize<'de> for MacAddr {
86 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>7x
87 where7x
88 D: de::Deserializer<'de>,7x
89 {
90 deserializer.deserialize_str(MacAddrVisitor)7x
91 }7x
92}
93
94#[cfg(test)]
95#[path = "net_test.rs"]
96mod tests;
97