Add random stuff
This commit is contained in:
commit
767331aa3d
|
@ -0,0 +1,5 @@
|
|||
|
||||
/target/
|
||||
**/*.rs.bk
|
||||
Cargo.lock
|
||||
/recovered_revisions/
|
|
@ -0,0 +1,8 @@
|
|||
[package]
|
||||
name = "uirc"
|
||||
version = "0.1.0"
|
||||
authors = ["SoniEx2 <endermoneymod@gmail.com>"]
|
||||
|
||||
[dependencies]
|
||||
arrayref = "0.3.4"
|
||||
matches = "0.1.6"
|
|
@ -0,0 +1,175 @@
|
|||
use std::fmt;
|
||||
use std::str::{from_utf8, from_utf8_unchecked};
|
||||
|
||||
/// An IRC command
|
||||
#[derive(Copy,Clone,Debug,Eq,PartialEq,Ord,PartialOrd)]
|
||||
pub enum IrcCommand<'a> {
|
||||
Stringy(Stringy<'a>),
|
||||
Numeric(Numeric<'a>)
|
||||
}
|
||||
|
||||
/// A stringy IRC command
|
||||
#[derive(Copy,Clone,Debug,Eq,PartialEq,Ord,PartialOrd)]
|
||||
pub struct Stringy<'a>(&'a [u8]);
|
||||
|
||||
/// A numeric IRC command.
|
||||
#[derive(Copy,Clone,Debug,Eq,PartialEq,Ord,PartialOrd)]
|
||||
pub struct Numeric<'a>(u16, &'a [u8; 3]);
|
||||
|
||||
/// A full IRC command line.
|
||||
pub trait IrcCommandLine {
|
||||
fn get_command<'a>(&'a self) -> IrcCommand<'a>;
|
||||
|
||||
/// Experimental. Do not use.
|
||||
fn get_argument<'a>(&'a self, arg: usize) -> &'a [u8];
|
||||
/// Experimental. Do not use.
|
||||
fn get_argument_count(&self) -> usize;
|
||||
/// Experimental. Do not use.
|
||||
fn get_source<'a>(&'a self) -> &'a [u8];
|
||||
}
|
||||
|
||||
impl<'a> Stringy<'a> {
|
||||
#[inline]
|
||||
pub fn new(cmd: &'a [u8]) -> Option<Stringy<'a>> {
|
||||
if cmd.len() == 3 && matches!((cmd[0], cmd[1], cmd[2]), (b'0'...b'9', b'0'...b'9', b'0'...b'9')) {
|
||||
None
|
||||
} else {
|
||||
Some(Self::new_unchecked(cmd))
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn new_unchecked(cmd: &'a [u8]) -> Stringy<'a> {
|
||||
Stringy(cmd)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get_bytes(&self) -> &'a [u8] {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
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!"),
|
||||
/// }
|
||||
/// ```
|
||||
#[inline]
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
/// 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_from_slice(b"005") {
|
||||
/// Some(numeric) => println!("Numeric: {}", numeric),
|
||||
/// None => println!("Not a numeric!"),
|
||||
/// }
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn new_from_slice(cmd: &'a [u8]) -> Option<Numeric<'a>> {
|
||||
if cmd.len() == 3 {
|
||||
// TODO switch to TryFrom/TryInto once those are stable. (rust-lang/rust#33417)
|
||||
Self::new(array_ref![cmd, 0, 3])
|
||||
} else {
|
||||
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 let Some(numeric) = Numeric::new_from_slice(cmd) {
|
||||
IrcCommand::Numeric(numeric)
|
||||
} else {
|
||||
IrcCommand::Stringy(Stringy::new(cmd).unwrap())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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)?;
|
||||
break;
|
||||
} 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)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
// What was I gonna put here?
|
||||
//
|
||||
// I didn't manage to recover this file from the depths of /dev/sdb1, so I don't know what it was
|
||||
// for.
|
|
@ -0,0 +1,10 @@
|
|||
#[macro_use]
|
||||
extern crate arrayref;
|
||||
#[macro_use]
|
||||
extern crate matches;
|
||||
|
||||
pub mod command;
|
||||
|
||||
pub mod commands;
|
||||
|
||||
pub mod simple;
|
|
@ -0,0 +1,38 @@
|
|||
use command::{IrcCommand, IrcCommandLine, Numeric, Stringy};
|
||||
|
||||
use std::io;
|
||||
use std::io::prelude::*;
|
||||
|
||||
use std::ops::Range;
|
||||
|
||||
pub struct SimpleIrcCommand {
|
||||
command: Vec<u8>,
|
||||
arguments: (Vec<Range<usize>>, Vec<u8>),
|
||||
source: Vec<u8>,
|
||||
}
|
||||
|
||||
impl IrcCommandLine for SimpleIrcCommand {
|
||||
fn get_command<'a>(&'a self) -> IrcCommand<'a> {
|
||||
IrcCommand::new(&self.command)
|
||||
}
|
||||
|
||||
fn get_argument<'a>(&'a self, arg: usize) -> &'a [u8] {
|
||||
&self.arguments.1[self.arguments.0[arg].clone()] // awful API there, rust.
|
||||
}
|
||||
|
||||
fn get_argument_count(&self) -> usize {
|
||||
self.arguments.0.len()
|
||||
}
|
||||
|
||||
fn get_source<'a>(&'a self) -> &'a [u8] {
|
||||
&self.source
|
||||
}
|
||||
}
|
||||
|
||||
pub struct NoIrcConnection;
|
||||
|
||||
impl NoIrcConnection {
|
||||
pub fn read_command<R: Read>(reader: R) -> io::Result<SimpleIrcCommand> {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue