use crate::AprsData;
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum DuplicateDecision {
New,
Duplicate,
}
impl DuplicateDecision {
#[must_use]
pub const fn code(self) -> &'static str {
match self {
Self::New => "duplicate.new",
Self::Duplicate => "duplicate.duplicate",
}
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct DuplicateWindow {
capacity: usize,
packets: Vec<Vec<u8>>,
}
impl DuplicateWindow {
#[must_use]
pub const fn new(capacity: usize) -> Self {
Self {
capacity,
packets: Vec::new(),
}
}
pub fn observe(&mut self, packet: &[u8]) -> DuplicateDecision {
if self.packets.iter().any(|existing| existing == packet) {
return DuplicateDecision::Duplicate;
}
if self.capacity > 0 {
if self.packets.len() == self.capacity {
self.packets.remove(0);
}
self.packets.push(packet.to_vec());
}
DuplicateDecision::New
}
#[must_use]
pub fn retained_len(&self) -> usize {
self.packets.len()
}
#[must_use]
pub const fn capacity(&self) -> usize {
self.capacity
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum RateLimitDecision {
Allowed,
Limited,
}
impl RateLimitDecision {
#[must_use]
pub const fn code(self) -> &'static str {
match self {
Self::Allowed => "rate.allowed",
Self::Limited => "rate.limited",
}
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct PacketRateBudget {
limit: u64,
remaining: u64,
}
impl PacketRateBudget {
#[must_use]
pub const fn new(limit: u64) -> Self {
Self {
limit,
remaining: limit,
}
}
pub fn try_consume(&mut self) -> RateLimitDecision {
if self.remaining == 0 {
return RateLimitDecision::Limited;
}
self.remaining -= 1;
RateLimitDecision::Allowed
}
pub fn reset(&mut self) {
self.remaining = self.limit;
}
#[must_use]
pub const fn limit(&self) -> u64 {
self.limit
}
#[must_use]
pub const fn remaining(&self) -> u64 {
self.remaining
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum SemanticFamily {
Status,
Position,
TimestampedPosition,
CompressedPosition,
Message,
Object,
Item,
Weather,
Telemetry,
TelemetryMetadata,
Query,
Capability,
Nmea,
MicE,
Maidenhead,
UserDefined,
ThirdParty,
Unsupported,
Malformed,
}
impl SemanticFamily {
#[must_use]
pub const fn from_aprs_data(data: &AprsData<'_>) -> Self {
match data {
AprsData::Status { .. } => Self::Status,
AprsData::Position(_) => Self::Position,
AprsData::TimestampedPosition(_) => Self::TimestampedPosition,
AprsData::CompressedPosition(_) => Self::CompressedPosition,
AprsData::Message(_) => Self::Message,
AprsData::Object(_) => Self::Object,
AprsData::Item(_) => Self::Item,
AprsData::Weather(_) => Self::Weather,
AprsData::Telemetry(_) => Self::Telemetry,
AprsData::TelemetryMetadata(_) => Self::TelemetryMetadata,
AprsData::Query(_) => Self::Query,
AprsData::Capability(_) => Self::Capability,
AprsData::Nmea(_) => Self::Nmea,
AprsData::MicE(_) => Self::MicE,
AprsData::Maidenhead(_) => Self::Maidenhead,
AprsData::UserDefined(_) => Self::UserDefined,
AprsData::ThirdParty(_) => Self::ThirdParty,
AprsData::Unsupported { .. } => Self::Unsupported,
AprsData::Malformed { .. } => Self::Malformed,
}
}
#[must_use]
pub const fn code(self) -> &'static str {
match self {
Self::Status => "status",
Self::Position => "position",
Self::TimestampedPosition => "timestamped_position",
Self::CompressedPosition => "compressed_position",
Self::Message => "message",
Self::Object => "object",
Self::Item => "item",
Self::Weather => "weather",
Self::Telemetry => "telemetry",
Self::TelemetryMetadata => "telemetry_metadata",
Self::Query => "query",
Self::Capability => "capability",
Self::Nmea => "nmea",
Self::MicE => "mic_e",
Self::Maidenhead => "maidenhead",
Self::UserDefined => "user_defined",
Self::ThirdParty => "third_party",
Self::Unsupported => "unsupported",
Self::Malformed => "malformed",
}
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct SemanticBlocklist<'a> {
families: &'a [SemanticFamily],
}
impl<'a> SemanticBlocklist<'a> {
#[must_use]
pub const fn new(families: &'a [SemanticFamily]) -> Self {
Self { families }
}
#[must_use]
pub fn rejects(&self, data: &AprsData<'_>) -> bool {
let family = SemanticFamily::from_aprs_data(data);
self.families.contains(&family)
}
#[must_use]
pub const fn families(&self) -> &'a [SemanticFamily] {
self.families
}
}