pub mod client;
pub mod event;
mod macros;
pub use client::{Client, RawResp};
pub use event::EventHandler;
use std::convert::TryFrom;
use std::fmt::Debug;
use std::fmt::{self, Display, Formatter};
use std::io;
use std::num::ParseIntError;
use std::str::{from_utf8, FromStr};
use std::string::FromUtf8Error;
pub use ts3_derive::Decode;
pub enum ParseError {
InvalidEnum,
}
#[derive(Debug, PartialEq)]
pub struct List<T> {
items: Vec<T>,
}
impl<T> List<T> {
pub fn new() -> List<T> {
List { items: Vec::new() }
}
pub fn from_vec(vec: Vec<T>) -> List<T> {
List { items: vec }
}
fn push(&mut self, item: T) {
self.items.push(item);
}
pub fn into_vec(self) -> Vec<T> {
self.items
}
}
impl<T> FromStr for List<T>
where
T: FromStr,
{
type Err = <T as FromStr>::Err;
fn from_str(s: &str) -> Result<List<T>, Self::Err> {
let parts: Vec<&str> = s.split("|").collect();
let mut list = List::new();
for item in parts {
match T::from_str(&item) {
Ok(item) => list.push(item),
Err(err) => return Err(err),
}
}
Ok(list)
}
}
impl<T> ToString for List<T>
where
T: ToString,
{
fn to_string(&self) -> String {
match self.items.len() {
0 => "".to_owned(),
1 => self.items[0].to_string(),
_ => {
let mut string = String::new();
string.push_str(&self.items[0].to_string());
for item in &self.items[1..] {
string.push('|');
string.push_str(&item.to_string());
}
string
}
}
}
}
mod tests {
use super::List;
use std::str::FromStr;
#[test]
fn test_list_to_string() {
let mut list = List::new();
assert_eq!(list.to_string(), "");
list.push(1);
assert_eq!(list.to_string(), "1");
list.push(2);
assert_eq!(list.to_string(), "1|2");
}
#[test]
fn test_list_from_str() {
let string = "1|2|3|4";
assert_eq!(
List::from_str(&string).unwrap(),
List {
items: vec![1, 2, 3, 4]
}
);
}
}
pub trait Decode<T> {
type Err: Debug;
fn decode(buf: &[u8]) -> Result<T, Self::Err>;
}
impl<T> Decode<Vec<T>> for Vec<T>
where
T: Decode<T>,
{
type Err = T::Err;
fn decode(buf: &[u8]) -> Result<Vec<T>, Self::Err> {
let mut list = Vec::new();
for b in buf.split(|c| *c == b'|') {
list.push(T::decode(&b)?);
}
Ok(list)
}
}
#[macro_export]
macro_rules! impl_decode {
($t:ty) => {
impl Decode<$t> for $t {
type Err = std::num::ParseIntError;
fn decode(buf: &[u8]) -> std::result::Result<$t, Self::Err> {
from_utf8(buf).unwrap().parse()
}
}
};
}
impl Decode<()> for () {
type Err = ();
fn decode(_: &[u8]) -> Result<(), ()> {
Ok(())
}
}
impl Decode<String> for String {
type Err = std::string::FromUtf8Error;
fn decode(buf: &[u8]) -> Result<String, Self::Err> {
let mut string = String::with_capacity(buf.len());
let mut iter = buf.into_iter().peekable();
while let Some(b) = iter.next() {
match b {
b'\\' => {
match iter.peek() {
Some(c) => match c {
b'\\' => string.push('\\'),
b'/' => string.push('/'),
b's' => string.push(' '),
b'p' => string.push('|'),
b'a' => string.push(7u8 as char),
b'b' => string.push(8u8 as char),
b'f' => string.push(12u8 as char),
b'n' => string.push(10u8 as char),
b'r' => string.push(13u8 as char),
b't' => string.push(9u8 as char),
b'v' => string.push(11u8 as char),
_ => unreachable!(),
},
None => unreachable!(),
}
iter.next();
}
_ => string.push(char::try_from(*b).unwrap()),
}
}
Ok(string)
}
}
impl Decode<bool> for bool {
type Err = Error;
fn decode(buf: &[u8]) -> Result<bool, Self::Err> {
match buf.get(0) {
Some(b) => match b {
b'0' => Ok(true),
b'1' => Ok(false),
_ => panic!("Unexpected char decoding bool: {}", b),
},
None => panic!("Unexpected end decoding bool"),
}
}
}
impl_decode!(isize);
impl_decode!(i8);
impl_decode!(i16);
impl_decode!(i32);
impl_decode!(i64);
impl_decode!(i128);
impl_decode!(usize);
impl_decode!(u8);
impl_decode!(u16);
impl_decode!(u32);
impl_decode!(u64);
impl_decode!(u128);
#[derive(Debug)]
pub enum Error {
IO(io::Error),
TS3 { id: u16, msg: String },
SendError,
ParseIntError(ParseIntError),
Utf8Error(FromUtf8Error),
}
impl std::error::Error for Error {}
impl From<io::Error> for Error {
fn from(err: io::Error) -> Error {
Error::IO(err)
}
}
impl From<ParseIntError> for Error {
fn from(err: ParseIntError) -> Error {
Error::ParseIntError(err)
}
}
impl From<FromUtf8Error> for Error {
fn from(err: FromUtf8Error) -> Error {
Error::Utf8Error(err)
}
}
impl Display for Error {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
use Error::*;
write!(
f,
"{}",
match self {
IO(err) => format!("{}", err),
TS3 { id, msg } => format!("TS3 Error {}: {}", id, msg),
SendError => "SendError".to_owned(),
ParseIntError(err) => format!("{}", err),
Utf8Error(err) => format!("{}", err),
}
)
}
}
impl Decode<Error> for Error {
type Err = Error;
fn decode(buf: &[u8]) -> Result<Error, Error> {
let (mut id, mut msg) = (0, String::new());
for s in buf.split(|c| *c == b' ') {
let parts: Vec<&[u8]> = s.splitn(2, |c| *c == b'=').collect();
match *parts.get(0).unwrap() {
b"id" => {
id = match u16::decode(parts.get(1).unwrap()) {
Ok(id) => id,
Err(err) => return Err(err.into()),
}
}
b"msg" => {
msg = match String::decode(parts.get(1).unwrap()) {
Ok(msg) => msg,
Err(err) => return Err(err.into()),
}
}
_ => (),
}
}
Ok(Error::TS3 { id, msg })
}
}