callpass 0.3.1

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

//! An APRS-IS passcode generator and type.
//!
//! # Usage
//!
//! The `Callpass` type is used for representing an APRS-IS passcode.
//! It will transform a callsign into a passcode, as well integers,
//! and can be used in place of integers where expecting a callpass.
//!
//! ```
//! let given_callsign = "x2yz".to_string();
//! let given_callpass = 29322i64;
//! ```
//!
//! We can generate a `Callpass` like so, using the From trait:
//!
//! ```
//! # use callpass::Callpass;
//! # let given_callsign = "x2yz".to_string();
//! // This step will generate an APRS-IS passcode.
//! let callpass: Callpass = given_callsign.into();
//! ```
//!
//! If we already have an APRS-IS passcode as an integer, we can
//! make a `Callpass` from that as well to gain the benefits of type
//! checking:
//!
//! ```
//! # use callpass::Callpass;
//! # let given_callpass = 29322i64;
//! let their_callpass: Callpass = given_callpass.into();
//!
//! assert!(their_callpass == given_callpass);
//! ```

#[macro_use]
mod impl_macro;

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

/// This type will generate and represent an APRS-IS passcode.
///
/// # Callpass generation
///
/// When given a callsign, an APRS-IS passcode will be generated.
///
/// ```
/// # use callpass::Callpass;
/// let callpass: Callpass = "x2yz".into();
/// ```
///
/// # Comparisons
///
/// Its value can be directly compared to other numbers.
///
/// ```
/// # use callpass::Callpass;
/// # let callpass: Callpass = "x2yz".into();
/// assert!(callpass == 29322);
/// ```
///
/// # Representation
///
/// A `Callpass` can also be used in place of integers.
///
/// ```
/// # use callpass::Callpass;
/// # let callpass: Callpass = "x2yz".into();
/// let given_passcode: Callpass = 29322.into();
/// assert!(callpass == given_passcode);
/// ```
///
/// A `Callpass` can also be used as an integer where required.
///
/// ```
/// # use callpass::Callpass;
/// # let callpass: Callpass = "x2yz".into();
/// fn i64_eater(lunch: i64) {}
///
/// i64_eater(callpass.into())
/// ```
///
/// # Modification
///
/// A `Callpass` will not allow modification (without being casted).
///
/// ```compile_fail
/// # use callpass::Callpass;
/// # let callpass: Callpass = "x2yz".into();
/// let changed_callpass = callpass + 4;
/// ```
///
/// ```compile_fail
/// # use callpass::Callpass;
/// # let mut callpass = Callpass "x2yz".into();
/// callpass.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()))
    }
}