blob: 41d1f71122b1bcce8855ecb0809076993846fe7f [file] [log] [blame]
// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//! A simple port manager.
use crate::hal;
use crate::{ElementId, Version};
use std::collections::HashMap;
pub type PortId = hal::PortId;
#[derive(Eq, PartialEq, Debug, Clone)]
pub struct Port {
pub e_id: ElementId,
pub port_id: PortId,
pub path: String,
}
impl Port {
//! new creates a physical port to be managed by the network manager.
pub fn new(port_id: PortId, path: &str, v: Version) -> Self {
//TODO(dpradilla) this has to check port actually exists and reference to it.
Port { e_id: ElementId::new(v), port_id, path: path.to_string() }
}
}
/// `PortManager` keeps track of physical ports in the system.
pub struct PortManager {
// ports keeps track of ports in the system and if they are available or not.
ports: std::collections::HashMap<PortId, (Port, bool)>,
}
impl PortManager {
//! Creates a new PortManager.
pub fn new() -> Self {
PortManager { ports: HashMap::new() }
}
/// `add_ports` adds a physical port to be manager by network manager.
pub fn add_port(&mut self, p: Port) {
// When adding a new port, is is considered available as no one has yet used it.
// If the port already exists, update the port, but keep availability unchanged.
let available =
if let Some((_, available)) = self.ports.get(&p.port_id) { *available } else { true };
self.ports.insert(p.port_id, (p, available));
}
/// `remove_ports` removes a port from port manager.
pub fn remove_port(&mut self, id: PortId) -> Option<Port> {
self.ports.remove(&id).map(|(p, _)| p)
}
/// `port` gets information about a port in port manager.
pub fn port(&self, id: PortId) -> Option<&Port> {
let (p, _) = self.ports.get(&id)?;
Some(&p)
}
/// `ports` returns all ports known by port manager.
pub fn ports(&self) -> impl ExactSizeIterator<Item = &Port> {
self.ports.iter().map(|(_, (p, _))| p)
}
/// `use_port` marks a port as in use, and returns true in that case.
/// It returns false if the port is already in use or doesnt exist.
pub fn use_port(&mut self, id: &PortId) -> bool {
if let Some((_, available)) = self.ports.get_mut(id) {
if *available {
// Make it unavailable.
*available = false;
return true;
}
}
false
}
/// `release_port` makes a port available if in use.
/// it does nothing if the port does not exist.
pub fn release_port(&mut self, id: &PortId) {
if let Some((_, available)) = self.ports.get_mut(id) {
if !*available {
// Make it available.
*available = true;
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
fn generate_path(id: u32) -> String {
"port".to_owned() + &id.to_string()
}
#[test]
fn test_new_port() {
let p = Port::new(PortId::from(1), &generate_path(1), 123);
assert_eq!(p.port_id, PortId::from(1));
assert_eq!(p.path, "port1");
assert_eq!(p.e_id.version, 123);
let p = Port::new(PortId::from(20), &generate_path(20), 95);
assert_eq!(p.port_id, PortId::from(20));
assert_eq!(p.path, "port20");
assert_eq!(p.e_id.version, 95);
}
#[test]
fn test_port_manager_new() {
let pm = PortManager::new();
assert_eq!(pm.ports.len(), 0);
}
#[test]
fn test_port_manager_add() {
let mut pm = PortManager::new();
pm.add_port(Port::new(PortId::from(1), &generate_path(1), 1));
pm.add_port(Port::new(PortId::from(5), &generate_path(5), 1));
pm.add_port(Port::new(PortId::from(2), &generate_path(2), 1));
assert_eq!(pm.ports.len(), 3);
}
#[test]
fn test_port_manager_add_existing() {
let mut pm = PortManager::new();
pm.add_port(Port::new(PortId::from(1), &generate_path(1), 1));
pm.add_port(Port::new(PortId::from(5), &generate_path(5), 1));
pm.add_port(Port::new(PortId::from(1), &generate_path(1), 1));
pm.add_port(Port::new(PortId::from(3), &generate_path(3), 1));
assert_eq!(pm.ports.len(), 3);
}
#[test]
fn test_port_manager_get_existing() {
let mut pm = PortManager::new();
pm.add_port(Port::new(PortId::from(1), &generate_path(1), 1));
let p = Port::new(PortId::from(5), &generate_path(5), 1);
pm.add_port(p.clone());
pm.add_port(Port::new(PortId::from(3), &generate_path(3), 1));
let got = pm.port(PortId::from(5));
assert_eq!(got, Some(&p))
}
#[test]
fn test_port_manager_get_inexisting() {
let mut pm = PortManager::new();
pm.add_port(Port::new(PortId::from(1), &generate_path(1), 1));
pm.add_port(Port::new(PortId::from(5), &generate_path(5), 1));
pm.add_port(Port::new(PortId::from(3), &generate_path(3), 1));
let got = pm.port(PortId::from(15));
assert_eq!(got, None)
}
#[test]
fn test_port_manager_update_existing() {
let mut pm = PortManager::new();
pm.add_port(Port::new(PortId::from(1), &generate_path(1), 1));
assert_eq!(pm.ports.len(), 1);
let p = pm.port(PortId::from(1)).unwrap();
assert_eq!(p.path, generate_path(1));
assert_eq!(p.port_id, PortId::from(1));
pm.add_port(Port::new(PortId::from(1), &generate_path(9), 9));
assert_eq!(pm.ports.len(), 1);
let p = pm.port(PortId::from(1)).unwrap();
assert_eq!(p.path, generate_path(9));
assert_eq!(p.port_id, PortId::from(1));
}
#[test]
fn test_port_manager_remove_existing() {
let mut pm = PortManager::new();
pm.add_port(Port::new(PortId::from(1), &generate_path(1), 1));
let p = Port::new(PortId::from(5), &generate_path(5), 1);
pm.add_port(p.clone());
pm.add_port(Port::new(PortId::from(3), &generate_path(3), 1));
let got = pm.remove_port(PortId::from(5));
assert_eq!(pm.ports.len(), 2);
assert_eq!(got, Some(p))
}
#[test]
fn test_port_manager_remove_inexisting() {
let mut pm = PortManager::new();
pm.add_port(Port::new(PortId::from(1), &generate_path(1), 1));
pm.add_port(Port::new(PortId::from(5), &generate_path(5), 1));
pm.add_port(Port::new(PortId::from(3), &generate_path(3), 1));
assert_eq!(pm.ports.len(), 3);
let got = pm.remove_port(PortId::from(6));
assert_eq!(pm.ports.len(), 3);
assert_eq!(got, None)
}
#[test]
fn test_port_manager_use() {
let mut pm = PortManager::new();
pm.add_port(Port::new(PortId::from(1), &generate_path(1), 1));
pm.add_port(Port::new(PortId::from(5), &generate_path(5), 1));
pm.add_port(Port::new(PortId::from(3), &generate_path(3), 1));
let got = pm.use_port(&PortId::from(5));
assert_eq!(got, true)
}
#[test]
fn test_port_manager_double_use() {
let mut pm = PortManager::new();
pm.add_port(Port::new(PortId::from(1), &generate_path(1), 1));
pm.add_port(Port::new(PortId::from(5), &generate_path(5), 1));
pm.add_port(Port::new(PortId::from(3), &generate_path(3), 1));
let got = pm.use_port(&PortId::from(5));
assert_eq!(got, true);
let got2 = pm.use_port(&PortId::from(5));
assert_eq!(got2, false)
}
#[test]
fn test_port_manager_use_inexisting() {
let mut pm = PortManager::new();
pm.add_port(Port::new(PortId::from(1), &generate_path(1), 1));
pm.add_port(Port::new(PortId::from(5), &generate_path(5), 1));
pm.add_port(Port::new(PortId::from(3), &generate_path(3), 1));
let got = pm.use_port(&PortId::from(15));
assert_eq!(got, false)
}
}