Skip to main content

leodos_protocols/network/isl/
torus.rs

1/// A point on a 2D grid.
2#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
3pub struct Point {
4    /// Orbital plane index.
5    pub orb: u8,
6    /// Satellite index within the orbital plane.
7    pub sat: u8,
8}
9
10impl Point {
11    /// Creates a new point from orbital plane and satellite indices.
12    pub fn new(orb: u8, sat: u8) -> Self {
13        Self { orb, sat }
14    }
15}
16
17/// Cardinal direction on the toroidal ISL grid.
18#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
19pub enum Direction {
20    /// Toward lower satellite index (intra-plane).
21    North,
22    /// Toward higher satellite index (intra-plane).
23    South,
24    /// Toward higher orbital plane index (cross-plane).
25    East,
26    /// Toward lower orbital plane index (cross-plane).
27    West,
28}
29
30impl Direction {
31    /// Returns the opposite direction.
32    pub fn opposite(self) -> Self {
33        match self {
34            Self::North => Self::South,
35            Self::South => Self::North,
36            Self::East => Self::West,
37            Self::West => Self::East,
38        }
39    }
40}
41
42/// Next-hop routing decision.
43#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
44pub enum Hop {
45    /// Forward on an ISL link.
46    Isl(Direction),
47    /// Send to the ground station.
48    Ground,
49    /// Deliver to the local node.
50    Local,
51}
52
53/// A 2D toroidal grid.
54#[derive(Debug, Copy, Clone)]
55pub struct Torus {
56    /// Number of orbital planes.
57    pub num_orbs: u8,
58    /// Number of satellites per orbital plane.
59    pub num_sats: u8,
60}
61
62impl Torus {
63    /// Creates a new torus with the given dimensions.
64    pub const fn new(num_orbs: u8, num_sats: u8) -> Self {
65        Self { num_orbs, num_sats }
66    }
67
68    /// Calculates the position of a neighbor in a given direction from a starting point.
69    pub fn neighbor(&self, point: Point, direction: Direction) -> Point {
70        match direction {
71            Direction::North => Point::new(point.orb, Self::prev(point.sat, self.num_sats)),
72            Direction::South => Point::new(point.orb, Self::next(point.sat, self.num_sats)),
73            Direction::East => Point::new(Self::next(point.orb, self.num_orbs), point.sat),
74            Direction::West => Point::new(Self::prev(point.orb, self.num_orbs), point.sat),
75        }
76    }
77
78    // --- Topology Helpers (Used by Strategies) ---
79
80    /// Returns the next index, wrapping around at `modulus`.
81    pub fn next(index: u8, modulus: u8) -> u8 {
82        if index == modulus - 1 { 0 } else { index + 1 }
83    }
84
85    /// Returns the previous index, wrapping around at `modulus`.
86    pub fn prev(index: u8, modulus: u8) -> u8 {
87        if index == 0 { modulus - 1 } else { index - 1 }
88    }
89
90    /// Returns the forward distance from `from` to `to` on a circular axis.
91    pub fn distance(from: u8, to: u8, modulus: u8) -> u8 {
92        if to >= from {
93            to - from
94        } else {
95            modulus - from + to
96        }
97    }
98
99    /// Returns the satellite index after `p.sat`, wrapping around.
100    pub fn next_sat(&self, p: Point) -> u8 {
101        Self::next(p.sat, self.num_sats)
102    }
103
104    /// Returns the satellite index before `p.sat`, wrapping around.
105    pub fn prev_sat(&self, p: Point) -> u8 {
106        Self::prev(p.sat, self.num_sats)
107    }
108
109    /// Returns the orbital plane index after `p.orb`, wrapping around.
110    pub fn next_orb(&self, p: Point) -> u8 {
111        Self::next(p.orb, self.num_orbs)
112    }
113
114    /// Returns the orbital plane index before `p.orb`, wrapping around.
115    pub fn prev_orb(&self, p: Point) -> u8 {
116        Self::prev(p.orb, self.num_orbs)
117    }
118
119    /// Returns the distance between two orbits.
120    pub fn distance_orb(&self, from: Point, to: Point) -> u8 {
121        Self::distance(from.orb, to.orb, self.num_orbs)
122    }
123
124    /// Returns the distance between two satellites.
125    pub fn distance_sat(&self, from: Point, to: Point) -> u8 {
126        Self::distance(from.sat, to.sat, self.num_sats)
127    }
128
129    /// Returns the direction to move from `from` to `to` along the satellite axis.
130    pub fn direction_to_sat(&self, from: Point, to: Point) -> Direction {
131        let north_dist = self.distance_sat(to, from);
132        let south_dist = self.distance_sat(from, to);
133        if north_dist < south_dist {
134            Direction::North
135        } else {
136            Direction::South
137        }
138    }
139
140    /// Returns the direction to move from `from` to `to` along the orbital plane axis.
141    pub fn direction_to_orb(&self, from: Point, to: Point) -> Direction {
142        let west_dist = self.distance_orb(to, from);
143        let east_dist = self.distance_orb(from, to);
144        if west_dist < east_dist {
145            Direction::West
146        } else {
147            Direction::East
148        }
149    }
150}