thingy/recovered_revisions/src/command_rs/file.381131137370

124 lines
3.5 KiB
Plaintext
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

use std::fmt;
use std::str::{from_utf8, from_utf8_unchecked};
#[derive(Copy,Clone,Debug,Eq,PartialEq,Ord,PartialOrd)]
pub enum IrcCommand<'a> {
Stringy(Stringy<'a>),
Numeric(Numeric<'a>)
}
#[derive(Copy,Clone,Debug,Eq,PartialEq,Ord,PartialOrd)]
pub struct Stringy<'a>(&'a [u8]);
#[derive(Copy,Clone,Debug,Eq,PartialEq,Ord,PartialOrd)]
pub struct Numeric<'a>(u16, &'a [u8; 3]);
pub trait IrcCommandLine {
fn get_command<'a>(&'a self) -> IrcCommand<'a>;
}
impl<'a> fmt::Display for Stringy<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut i = 0;
let l = self.0.len();
let v = self.0;
while i < l {
let st = from_utf8(&v[i..]);
if let Ok(s) = st {
write!(f, "{}", s)?;
} else {
let err = st.err().unwrap();
write!(f, "{}", unsafe { from_utf8_unchecked(&v[i..][..err.valid_up_to()])})?;
write!(f, "\u{FFFD}")?;
match err.error_len() {
None => i = l,
Some(len) => i = i + err.valid_up_to() + len
}
}
}
Ok(())
}
}
impl<'a> fmt::Display for Numeric<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.0)
}
}
impl<'a> Stringy<'a> {
}
impl<'a> Numeric<'a> {
/// Creates a new numeric from the given bytes. Returns None if the given bytes aren't a valid
/// numeric.
///
/// # Examples
/// ```
/// use uirc::command::Numeric;
///
/// match Numeric::new(b"005") {
/// Some(numeric) => println!("Numeric: {}", numeric),
/// None => println!("Not a numeric!"),
/// }
/// ```
pub fn new(cmd: &'a [u8; 3]) -> Option<Numeric<'a>> {
match (cmd[0], cmd[1], cmd[2]) {
(b'0'...b'9', b'0'...b'9', b'0'...b'9') => Some(Numeric::new_unchecked(cmd)),
_ => None
}
}
// not unsafe, but may produce unexpected results
// keep this private (for now)
#[inline]
fn new_unchecked(cmd: &'a [u8; 3]) -> Numeric<'a> {
Numeric(cmd.iter().map(|x| (x-b'0') as u16).fold(0, |x,y| x*10+y), cmd)
}
/// Returns the numeric as a number, e.g. for processing in code.
///
/// # Examples
/// ```
/// use uirc::command::Numeric;
///
/// let numeric = Numeric::new(b"005").unwrap();
/// match numeric.get_numeric() {
/// 005 => println!("got an ISUPPORT!"),
/// _ => println!("got something else!"),
/// }
/// ```
#[inline]
pub fn get_numeric(&self) -> u16 {
self.0
}
/// Returns the numeric as bytes, e.g. for writing to a stream.
///
/// # Examples
/// ```rust
/// use uirc::command::Numeric;
/// use std::io::Write;
///
/// let mut client = Vec::new();
/// let numeric = Numeric::new(b"005").unwrap();
/// let bytes = numeric.get_bytes();
/// client.write_all(bytes).unwrap();
/// ```
#[inline]
pub fn get_bytes(&self) -> &'a [u8; 3] {
self.1
}
}
impl<'a> IrcCommand<'a> {
pub fn new(cmd: &'a [u8]) -> IrcCommand<'a> {
if cmd.len() == 3 && matches!((cmd[0], cmd[1], cmd[2]), (b'0'...b'9', b'0'...b'9', b'0'...b'9')) {
// TODO switch to TryFrom/TryInto once those are stable. (rust-lang/rust#33417)
IrcCommand::Numeric(Numeric::new_unchecked(array_ref![cmd,0,3]))
} else {
IrcCommand::Stringy(Stringy(cmd))
}
}
}