hamaddr 0.1.0

Rust implementation of the ARNCE.
Documentation
// Copyright (c) 2022, The ARNGLL-Rust Authors.
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

use crate::HamAddrType;
use core::fmt;
use core::fmt::{Debug, Display, Formatter};

pub type Result<T = (), E = Error> = core::result::Result<T, E>;

/// Error type used by fallible `HamAddr` parsing and conversions.
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub enum Error {
    /// The input slice length was not one of the supported ARNCE lengths.
    InvalidSliceLength,

    /// The raw `~` notation is not supported for the provided input.
    UnsupportedRawNotation,

    /// The provided callsign exceeds the maximum encodable length.
    CallsignTooLong,

    /// The address cannot be represented in the target EUI form.
    HamAddrTooBig,

    /// The conversion from the given address type to EUI48 is invalid.
    CannotConvertToEui48(HamAddrType),

    /// The conversion from the given address type to EUI64 is invalid.
    CannotConvertToEui64(HamAddrType),

    /// Multicast addresses cannot be converted into an EUI64.
    MulticastEui64NotSupported,

    /// The EUI48 payload did not encode a callsign.
    Eui48MissingCallsign,

    /// The EUI64 payload did not encode a callsign.
    Eui64MissingCallsign,

    /// A callsign character was invalid at a specific offset.
    InvalidCharAt(InvalidCharAt),

    /// A callsign character was invalid.
    InvalidChar(InvalidChar),

    /// A 16-bit ARNCE chunk was invalid.
    InvalidChunk(InvalidChunk),
}

impl Display for Error {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        match self {
            Self::InvalidSliceLength => f.write_str("invalid slice length"),
            Self::UnsupportedRawNotation => f.write_str("unsupported raw notation"),
            Self::CallsignTooLong => f.write_str("callsign too long"),
            Self::HamAddrTooBig => f.write_str("HamAddr too big"),
            Self::CannotConvertToEui48(kind) => write!(f, "cannot convert {kind:?} to EUI48"),
            Self::CannotConvertToEui64(kind) => write!(f, "cannot convert {kind:?} to EUI64"),
            Self::MulticastEui64NotSupported => {
                f.write_str("multicast EUI64 conversion not supported")
            }
            Self::Eui48MissingCallsign => f.write_str("EUI48 did not contain a callsign"),
            Self::Eui64MissingCallsign => f.write_str("EUI64 did not contain a callsign"),
            Self::InvalidCharAt(error) => Display::fmt(error, f),
            Self::InvalidChar(error) => Display::fmt(error, f),
            Self::InvalidChunk(error) => Display::fmt(error, f),
        }
    }
}

impl core::error::Error for Error {}

impl From<InvalidCharAt> for Error {
    fn from(value: InvalidCharAt) -> Self {
        Self::InvalidCharAt(value)
    }
}

impl From<InvalidChar> for Error {
    fn from(value: InvalidChar) -> Self {
        Self::InvalidChar(value)
    }
}

impl From<InvalidChunk> for Error {
    fn from(value: InvalidChunk) -> Self {
        Self::InvalidChunk(value)
    }
}

/// Error type indicating an invalid character at a specific index.
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub struct InvalidCharAt(pub usize);

impl Display for InvalidCharAt {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        write!(f, "invalid character at index {}", self.0)
    }
}

impl core::error::Error for InvalidCharAt {}

/// Error type indicating that the character was not valid.
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub struct InvalidChar;

impl Display for InvalidChar {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        f.write_str("invalid character")
    }
}

impl core::error::Error for InvalidChar {}

/// Error type indicating that the given 16-bit chunk does not decode properly.
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub struct InvalidChunk;

impl Display for InvalidChunk {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        f.write_str("invalid chunk")
    }
}

impl core::error::Error for InvalidChunk {}