1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179
#![cfg_attr(not(feature = "std"), no_std)]
#![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, and can be used in
//! place of integers where expecting a callpass.
//!
//! ```
//! let given_callsign = "x2yz";
//! let given_callpass = 29322i64;
//! ```
//!
//! We can generate a `Callpass` like so, using the From trait:
//!
//! ```
//! # use callpass::Callpass;
//! # let given_callsign = "x2yz";
//! // 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);
//! ```
extern crate ascii;
#[macro_use]
mod impl_macro;
#[cfg(feature = "std")]
use ascii::AsAsciiStr;
use ascii::AsciiStr;
#[cfg(feature = "std")]
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 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: &AsciiStr) -> Callpass {
Callpass({
let (hash, _) = callsign
.into_iter()
// Callsigns are always uppercase,
// and their u16 value is used for the hash
.map(|char| {
let mut d = *char;
d.make_ascii_uppercase();
d.as_byte() as u16
})
// Seed value provided, and a loop switch
.fold((0x73e2, true), |(hash, switch), input| {
let hash = match switch {
true => hash ^ input << 8,
false => hash ^ input,
};
(hash, !switch)
});
hash & 0x7fff
})
}
}
generate_impl_from_numeric!(u16, i16, u32, i32, u64, i64);
generate_impl_partialeq!(u16, i16, u32, i32, u64, i64);
#[cfg(feature = "std")]
impl Display for Callpass {
fn fmt(&self, f: &mut Formatter) -> Result {
write!(f, "{:05}", self.0)
}
}
#[cfg(feature = "std")]
impl From<Callpass> for String {
fn from(callpass: Callpass) -> String {
format!("{:05}", callpass)
}
}
#[cfg(feature = "std")]
impl From<String> for Callpass {
fn from(callsign: String) -> Self {
match callsign.as_ascii_str() {
Ok(ascii_call) => Callpass::new(ascii_call),
Err(err) => panic!("{}", &err),
}
}
}
#[cfg(feature = "std")]
impl<'a> From<&'a String> for Callpass {
fn from(callsign: &'a String) -> Self {
match callsign.as_ascii_str() {
Ok(ascii_call) => Callpass::new(ascii_call),
Err(err) => panic!("{}", &err),
}
}
}
impl<'a> From<&'a str> for Callpass {
fn from(callsign: &'a str) -> Self {
match AsciiStr::from_ascii(callsign) {
Ok(ascii_str) => Callpass::new(ascii_str),
Err(err) => panic!("{}", &err),
}
}
}