Skip to content

Commit eb935b6

Browse files
committed
refactor: overhaul & simplify internal types
- AddressFamily - - rename enum variants to Inet / Inet6 / Any - - serialize as "inet4" / "inet6" to align with ssh config - - accept aliases "4" / "6" - - no need to use IntOrString now we've changed config file format - PortRange - - no need to deserialise via IntOrString - - drop From<u64> - - derive Default - HumanU64 - - no need to deserialize from IntOrString - - ser/de as string for now - drop IntOrString as no longer used
1 parent 9f4d03a commit eb935b6

File tree

7 files changed

+69
-190
lines changed

7 files changed

+69
-190
lines changed

src/cli/args.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,9 +100,9 @@ impl CliArgs {
100100
CliArgs::from_arg_matches(&cli.get_matches_from(std::env::args_os())).unwrap();
101101
// Custom logic: '-4' and '-6' convenience aliases
102102
if args.ipv4_alias__ {
103-
args.config.address_family = Some(AddressFamily::V4);
103+
args.config.address_family = Some(AddressFamily::Inet);
104104
} else if args.ipv6_alias__ {
105-
args.config.address_family = Some(AddressFamily::V6);
105+
args.config.address_family = Some(AddressFamily::Inet6);
106106
}
107107
args
108108
}

src/util/address_family.rs

Lines changed: 47 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -1,142 +1,97 @@
11
//! CLI helper - Address family
22
// (c) 2024 Ross Younger
33

4-
use std::fmt::Display;
5-
use std::marker::PhantomData;
64
use std::str::FromStr;
75

8-
use figment::error::Actual;
9-
use serde::Serialize;
6+
use figment::error::{Actual, OneOf};
7+
use serde::{de, Deserialize, Serialize};
108

11-
use crate::util::cli::IntOrString;
12-
13-
/// Representation an IP address family
9+
/// Representation of an IP address family
1410
///
15-
/// This is a local type with special parsing semantics to take part in the config/CLI system.
16-
#[derive(Debug, Clone, Copy, PartialEq, Eq, clap::ValueEnum)]
11+
/// This is a local type with special parsing semantics and aliasing to take part in the config/CLI system.
12+
#[derive(Debug, Clone, Copy, PartialEq, Eq, clap::ValueEnum, Serialize)]
13+
#[serde(rename_all = "kebab-case")] // to match clap::ValueEnum
1714
pub enum AddressFamily {
1815
/// IPv4
19-
#[value(name = "4")]
20-
V4,
16+
#[value(alias("4"), alias("inet4"))]
17+
Inet,
2118
/// IPv6
22-
#[value(name = "6")]
23-
V6,
19+
#[value(alias("6"))]
20+
Inet6,
2421
/// We don't mind what type of IP address
2522
Any,
2623
}
2724

28-
impl From<AddressFamily> for u8 {
29-
fn from(value: AddressFamily) -> Self {
30-
match value {
31-
AddressFamily::V4 => 4,
32-
AddressFamily::V6 => 6,
33-
AddressFamily::Any => 0,
34-
}
35-
}
36-
}
37-
38-
impl Serialize for AddressFamily {
39-
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
40-
where
41-
S: serde::Serializer,
42-
{
43-
match *self {
44-
AddressFamily::Any => serializer.serialize_str("any"),
45-
t => serializer.serialize_u8(u8::from(t)),
46-
}
47-
}
48-
}
49-
50-
impl Display for AddressFamily {
51-
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
52-
if *self == AddressFamily::Any {
53-
write!(f, "any")
54-
} else {
55-
write!(f, "{}", u8::from(*self))
56-
}
57-
}
58-
}
59-
6025
impl FromStr for AddressFamily {
6126
type Err = figment::Error;
6227

6328
fn from_str(s: &str) -> Result<Self, Self::Err> {
64-
if s == "4" {
65-
Ok(AddressFamily::V4)
66-
} else if s == "6" {
67-
Ok(AddressFamily::V6)
68-
} else if s == "0" || s == "any" {
69-
Ok(AddressFamily::Any)
70-
} else {
71-
Err(figment::error::Kind::InvalidType(Actual::Str(s.into()), "4 or 6".into()).into())
72-
}
73-
}
74-
}
75-
76-
impl TryFrom<u64> for AddressFamily {
77-
type Error = figment::Error;
78-
79-
fn try_from(value: u64) -> Result<Self, Self::Error> {
80-
match value {
81-
4 => Ok(AddressFamily::V4),
82-
6 => Ok(AddressFamily::V6),
83-
0 => Ok(AddressFamily::Any),
84-
_ => Err(figment::error::Kind::InvalidValue(
85-
Actual::Unsigned(value.into()),
86-
"4 or 6".into(),
29+
match s {
30+
"4" | "inet" | "inet4" => Ok(AddressFamily::Inet),
31+
"6" | "inet6" => Ok(AddressFamily::Inet6),
32+
"any" => Ok(AddressFamily::Any),
33+
_ => Err(figment::error::Kind::InvalidType(
34+
Actual::Str(s.into()),
35+
OneOf(&["inet", "4", "inet6", "6"]).to_string(),
8736
)
8837
.into()),
8938
}
9039
}
9140
}
9241

93-
impl<'de> serde::Deserialize<'de> for AddressFamily {
42+
impl<'de> Deserialize<'de> for AddressFamily {
9443
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
9544
where
9645
D: serde::Deserializer<'de>,
9746
{
98-
deserializer.deserialize_any(IntOrString(PhantomData))
47+
let s = String::deserialize(deserializer)?;
48+
FromStr::from_str(&s).map_err(de::Error::custom)
9949
}
10050
}
10151

10252
#[cfg(test)]
10353
mod test {
54+
use std::str::FromStr;
55+
10456
use super::AddressFamily;
10557

10658
#[test]
10759
fn serialize() {
108-
let a = AddressFamily::V4;
109-
let b = AddressFamily::V6;
60+
let a = AddressFamily::Inet;
61+
let b = AddressFamily::Inet6;
62+
let c = AddressFamily::Any;
11063

11164
let aa = serde_json::to_string(&a);
11265
let bb = serde_json::to_string(&b);
113-
assert_eq!(aa.unwrap(), "4");
114-
assert_eq!(bb.unwrap(), "6");
66+
let cc = serde_json::to_string(&c);
67+
assert_eq!(aa.unwrap(), "\"inet\"");
68+
assert_eq!(bb.unwrap(), "\"inet6\"");
69+
assert_eq!(cc.unwrap(), "\"any\"");
11570
}
11671

11772
#[test]
11873
fn deser_str() {
119-
let a: AddressFamily = serde_json::from_str(r#" "4" "#).unwrap();
120-
assert_eq!(a, AddressFamily::V4);
121-
let a: AddressFamily = serde_json::from_str(r#" "6" "#).unwrap();
122-
assert_eq!(a, AddressFamily::V6);
123-
}
124-
125-
#[test]
126-
fn deser_int() {
127-
let a: AddressFamily = serde_json::from_str("4").unwrap();
128-
assert_eq!(a, AddressFamily::V4);
129-
let a: AddressFamily = serde_json::from_str("6").unwrap();
130-
assert_eq!(a, AddressFamily::V6);
74+
use AddressFamily::*;
75+
for (str, expected) in &[
76+
("4", Inet),
77+
("inet", Inet),
78+
("inet4", Inet),
79+
("6", Inet6),
80+
("inet6", Inet6),
81+
("any", Any),
82+
] {
83+
let raw = AddressFamily::from_str(str).expect(str);
84+
let json = format!(r#""{str}""#);
85+
let output = serde_json::from_str::<AddressFamily>(&json).expect(str);
86+
assert_eq!(raw, *expected);
87+
assert_eq!(output, *expected);
88+
}
13189
}
13290

13391
#[test]
13492
fn deser_invalid() {
135-
let _ = serde_json::from_str::<AddressFamily>("true").unwrap_err();
136-
let _ = serde_json::from_str::<AddressFamily>("5").unwrap_err();
137-
let _ = serde_json::from_str::<AddressFamily>(r#" "5" "#).unwrap_err();
138-
let _ = serde_json::from_str::<AddressFamily>("-1").unwrap_err();
139-
let _ = serde_json::from_str::<AddressFamily>(r#" "42" "#).unwrap_err();
140-
let _ = serde_json::from_str::<AddressFamily>(r#" "string" "#).unwrap_err();
93+
for s in &["true", "5", r#""5""#, "-1", r#""42"#, r#""string"#] {
94+
let _ = serde_json::from_str::<AddressFamily>(s).expect_err(s);
95+
}
14196
}
14297
}

src/util/cli.rs

Lines changed: 0 additions & 51 deletions
This file was deleted.

src/util/dns.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@ pub fn lookup_host_by_family(host: &str, desired: AddressFamily) -> anyhow::Resu
1919

2020
let found = match desired {
2121
AddressFamily::Any => it.next(),
22-
AddressFamily::V4 => it.find(|addr| addr.is_ipv4()),
23-
AddressFamily::V6 => it.find(|addr| addr.is_ipv6()),
22+
AddressFamily::Inet => it.find(|addr| addr.is_ipv4()),
23+
AddressFamily::Inet6 => it.find(|addr| addr.is_ipv6()),
2424
};
2525
found
2626
.map(std::borrow::ToOwned::to_owned)

src/util/humanu64.rs

Lines changed: 13 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,21 @@
11
//! Serialization helper type - u64 parseable by humanize_rs
22
// (c) 2024 Ross Younger
33

4-
use std::{marker::PhantomData, ops::Deref, str::FromStr};
4+
use std::{ops::Deref, str::FromStr};
55

66
use humanize_rs::bytes::Bytes;
77
use serde::{
88
de::{self, Error as _},
99
Serialize,
1010
};
1111

12-
use super::cli::IntOrString;
13-
14-
/// An integer field that may also be expressed using engineering prefixes (k, M, G, etc).
12+
/// An integer field that may also be expressed using SI notation (k, M, G, etc).
1513
/// For example, `1k` and `1000` are the same.
1614
///
1715
/// (Nerdy description: This is a newtype wrapper to `u64` that adds a flexible deserializer via `humanize_rs::bytes::Bytes<u64>`.)
1816
1917
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize)]
20-
#[serde(from = "IntOrString<HumanU64>", into = "u64")]
18+
#[serde(from = "String", into = "String")]
2119
pub struct HumanU64(pub u64);
2220

2321
impl HumanU64 {
@@ -42,6 +40,12 @@ impl From<HumanU64> for u64 {
4240
}
4341
}
4442

43+
impl From<HumanU64> for String {
44+
fn from(value: HumanU64) -> Self {
45+
format!("{}", *value)
46+
}
47+
}
48+
4549
impl FromStr for HumanU64 {
4650
type Err = figment::Error;
4751

@@ -71,14 +75,8 @@ impl<'de> serde::Deserialize<'de> for HumanU64 {
7175
where
7276
D: serde::Deserializer<'de>,
7377
{
74-
deserializer.deserialize_any(IntOrString(PhantomData))
75-
}
76-
}
77-
78-
#[cfg(test)]
79-
impl rand::prelude::Distribution<HumanU64> for rand::distributions::Standard {
80-
fn sample<R: rand::Rng + ?Sized>(&self, rng: &mut R) -> HumanU64 {
81-
rng.gen::<u64>().into()
78+
let s = String::deserialize(deserializer)?;
79+
FromStr::from_str(&s).map_err(de::Error::custom)
8280
}
8381
}
8482

@@ -105,21 +103,15 @@ mod test {
105103
test_deser_str("\"100k\"", 100_000);
106104
}
107105

108-
#[test]
109-
fn deser_raw_int() {
110-
let foo: HumanU64 = serde_json::from_str("12345").unwrap();
111-
assert_eq!(*foo, 12345);
112-
}
113-
114106
#[test]
115107
fn serde_test() {
116108
let bw = HumanU64::new(42);
117-
assert_tokens(&bw, &[Token::U64(42)]);
109+
assert_tokens(&bw, &[Token::Str("42")]);
118110
}
119111

120112
#[test]
121113
fn from_int() {
122-
let result = HumanU64::from(12345);
114+
let result = HumanU64::new(12345);
123115
assert_eq!(*result, 12345);
124116
}
125117
#[test]

src/util/mod.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,6 @@ pub use dns::lookup_host_by_family;
1010
mod cert;
1111
pub use cert::Credentials;
1212

13-
pub mod cli;
14-
1513
pub mod humanu64;
1614
pub mod io;
1715
pub mod socket;

0 commit comments

Comments
 (0)