callpass 0.3.0

Generate APRS passcodes
Documentation
#![deny(missing_docs)]

//! An APRS-IS passcode generator and type!
//!
//! # Usage
//!
//! The current convention exclusively uses From:
//!
//! ```
//! use callpass::Callpass;
//! let _: Callpass = "x2yz".into();
//! ```
//!
//! ```
//! use callpass::Callpass;
//! let x2yz: String = "x2yz".to_string();
//! let _: Callpass = x2yz.into();
//! ```
//!
//! It can also be used in place of various integers.
//!
//! ```
//! use callpass::Callpass;
//!
//! let given_callpass: i64 = 29322i64;
//! let callpass: Callpass = given_callpass.into();
//!
//! assert!(callpass == given_callpass);
//! ```

#[macro_use]
mod impl_macro;

use std::fmt::{Display, Formatter, Result};

/// This represents an APRS-IS passcode.
///
/// # Comparisons
///
/// Its value can be directly compared to other numbers.
///
/// ```
/// use callpass::Callpass;
/// let callpass: Callpass = "x2yz".into();
/// assert!(callpass == 29322);
/// ```
///
/// # Modification
///
/// It cannot be modified without being casted.
///
/// ```compile_fail
/// use callpass::Callpass;
/// let m: Callpass = "x2yz".into();
/// let n = m + 4;
/// ```
///
/// ```compile_fail
/// use callpass::Callpass;
/// let m = Callpass "x2yz".into();
/// m.0 = 12345;
/// ```
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd)]
pub struct Callpass(u16);

impl Callpass {
    fn new(callsign: &String) -> Callpass {
        Callpass({
            let mut hash: u16 = 0x73e2; // seed value
            let mut i = true; // loop switch
            for x in callsign.chars() {
                let x = x.to_uppercase().next().unwrap() as u16;
                match i {
                    true => hash = hash ^ x << 8,
                    false => hash = hash ^ x,
                };
                i = !i;
            }
            hash & 0x7fff
        })
    }
}

generate_impl_into!(u16, i16, u32, i32, u64, i64);

generate_impl_from!(u16, i16, u32, i32, u64, i64);

generate_impl_partialeq!(u16, i16, u32, i32, u64, i64);

impl Display for Callpass {
    fn fmt(&self, f: &mut Formatter) -> Result {
        write!(f, "{:05}", self.0)
    }
}

impl Into<String> for Callpass {
    fn into(self) -> String {
        self.0.to_string()
    }
}

impl From<String> for Callpass {
    fn from(callsign: String) -> Self {
        Callpass::new(&callsign)
    }
}

impl<'a> From<&'a String> for Callpass {
    fn from(callsign: &'a String) -> Self {
        Callpass::new(callsign)
    }
}

impl<'a> From<&'a str> for Callpass {
    fn from(callsign: &'a str) -> Self {
        Callpass::new(&(callsign.to_string()))
    }
}