Merge remote-tracking branch 'origin/master' into feat/postgresqlScore
Some checks failed
Run Check Script / check (pull_request) Failing after 1s

This commit is contained in:
2026-01-06 13:44:50 -05:00
72 changed files with 1899 additions and 481 deletions

View File

@@ -10,3 +10,4 @@ serde.workspace = true
url.workspace = true
rand.workspace = true
serde_json.workspace = true
log.workspace = true

View File

@@ -1,3 +1,5 @@
use log::trace;
use serde::Serialize;
use std::{fmt, str::FromStr};
/// Simple error type for port parsing failures.
@@ -21,7 +23,7 @@ impl fmt::Display for PortParseError {
/// Represents the atomic, physical location of a switch port: `<Stack>/<Module>/<Port>`.
///
/// Example: `1/1/1`
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Serialize)]
pub struct PortLocation(pub u8, pub u8, pub u8);
impl fmt::Display for PortLocation {
@@ -70,6 +72,12 @@ impl FromStr for PortLocation {
pub enum PortDeclaration {
/// A single switch port defined by its location. Example: `PortDeclaration::Single(1/1/1)`
Single(PortLocation),
/// A Named port, often used for virtual ports such as PortChannels. Example
/// ```rust
/// # use harmony_types::switch::PortDeclaration;
/// PortDeclaration::Named("1".to_string());
/// ```
Named(String),
/// A strictly sequential range defined by two endpoints using the hyphen separator (`-`).
/// All ports between the endpoints (inclusive) are implicitly included.
/// Example: `PortDeclaration::Range(1/1/1, 1/1/4)`
@@ -130,8 +138,25 @@ impl PortDeclaration {
return Ok(PortDeclaration::Set(start_port, end_port));
}
let location = PortLocation::from_str(port_str)?;
Ok(PortDeclaration::Single(location))
match PortLocation::from_str(port_str) {
Ok(loc) => Ok(PortDeclaration::Single(loc)),
Err(e) => {
let segments: Vec<&str> = port_str.split('/').collect();
let segment_count = segments.len();
// Logic:
// If it has 3 segments but failed (e.g., "1/A/1"), it's an InvalidSegment.
// If it has MORE than 3 segments (e.g., "1/1/1/1" or "1/1/1/"), it's an InvalidFormat.
if segment_count >= 3 {
return Err(e);
}
// Otherwise, it's something else entirely (e.g., "eth0", "vlan10"),
// so we treat it as a Named port.
trace!("Falling back on named port for: {port_str}");
Ok(PortDeclaration::Named(port_str.to_string()))
}
}
}
}
@@ -141,6 +166,7 @@ impl fmt::Display for PortDeclaration {
PortDeclaration::Single(port) => write!(f, "{port}"),
PortDeclaration::Range(start, end) => write!(f, "{start}-{end}"),
PortDeclaration::Set(start, end) => write!(f, "{start}*{end}"),
PortDeclaration::Named(name) => write!(f, "{name}"),
}
}
}