Browse Source

Add random stuff

SoniEx2 7 months ago
commit
767331aa3d
6 changed files with 240 additions and 0 deletions
  1. 5
    0
      .gitignore
  2. 8
    0
      Cargo.toml
  3. 175
    0
      src/command.rs
  4. 4
    0
      src/commands.rs
  5. 10
    0
      src/lib.rs
  6. 38
    0
      src/simple.rs

+ 5
- 0
.gitignore View File

@@ -0,0 +1,5 @@
1
+
2
+/target/
3
+**/*.rs.bk
4
+Cargo.lock
5
+/recovered_revisions/

+ 8
- 0
Cargo.toml View File

@@ -0,0 +1,8 @@
1
+[package]
2
+name = "uirc"
3
+version = "0.1.0"
4
+authors = ["SoniEx2 <endermoneymod@gmail.com>"]
5
+
6
+[dependencies]
7
+arrayref = "0.3.4"
8
+matches = "0.1.6"

+ 175
- 0
src/command.rs View File

@@ -0,0 +1,175 @@
1
+use std::fmt;
2
+use std::str::{from_utf8, from_utf8_unchecked};
3
+
4
+/// An IRC command
5
+#[derive(Copy,Clone,Debug,Eq,PartialEq,Ord,PartialOrd)]
6
+pub enum IrcCommand<'a> {
7
+    Stringy(Stringy<'a>),
8
+    Numeric(Numeric<'a>)
9
+}
10
+
11
+/// A stringy IRC command
12
+#[derive(Copy,Clone,Debug,Eq,PartialEq,Ord,PartialOrd)]
13
+pub struct Stringy<'a>(&'a [u8]);
14
+
15
+/// A numeric IRC command.
16
+#[derive(Copy,Clone,Debug,Eq,PartialEq,Ord,PartialOrd)]
17
+pub struct Numeric<'a>(u16, &'a [u8; 3]);
18
+
19
+/// A full IRC command line.
20
+pub trait IrcCommandLine {
21
+    fn get_command<'a>(&'a self) -> IrcCommand<'a>;
22
+
23
+    /// Experimental. Do not use.
24
+    fn get_argument<'a>(&'a self, arg: usize) -> &'a [u8];
25
+    /// Experimental. Do not use.
26
+    fn get_argument_count(&self) -> usize;
27
+    /// Experimental. Do not use.
28
+    fn get_source<'a>(&'a self) -> &'a [u8];
29
+}
30
+
31
+impl<'a> Stringy<'a> {
32
+    #[inline]
33
+    pub fn new(cmd: &'a [u8]) -> Option<Stringy<'a>> {
34
+        if cmd.len() == 3 && matches!((cmd[0], cmd[1], cmd[2]), (b'0'...b'9', b'0'...b'9', b'0'...b'9')) {
35
+            None
36
+        } else {
37
+            Some(Self::new_unchecked(cmd))
38
+        }
39
+    }
40
+
41
+    #[inline]
42
+    fn new_unchecked(cmd: &'a [u8]) -> Stringy<'a> {
43
+        Stringy(cmd)
44
+    }
45
+
46
+    #[inline]
47
+    pub fn get_bytes(&self) -> &'a [u8] {
48
+        self.0
49
+    }
50
+}
51
+
52
+impl<'a> Numeric<'a> {
53
+    /// Creates a new numeric from the given bytes. Returns None if the given bytes aren't a valid
54
+    /// numeric.
55
+    /// 
56
+    /// # Examples
57
+    /// ```
58
+    /// use uirc::command::Numeric;
59
+    ///
60
+    /// match Numeric::new(b"005") {
61
+    ///     Some(numeric) => println!("Numeric: {}", numeric),
62
+    ///     None => println!("Not a numeric!"),
63
+    /// }
64
+    /// ```
65
+    #[inline]
66
+    pub fn new(cmd: &'a [u8; 3]) -> Option<Numeric<'a>> {
67
+        match (cmd[0], cmd[1], cmd[2]) {
68
+            (b'0'...b'9', b'0'...b'9', b'0'...b'9') => Some(Numeric::new_unchecked(cmd)),
69
+            _ => None
70
+        }
71
+    }
72
+
73
+    /// Creates a new numeric from the given bytes. Returns None if the given bytes aren't a valid
74
+    /// numeric.
75
+    /// 
76
+    /// # Examples
77
+    /// ```
78
+    /// use uirc::command::Numeric;
79
+    ///
80
+    /// match Numeric::new_from_slice(b"005") {
81
+    ///     Some(numeric) => println!("Numeric: {}", numeric),
82
+    ///     None => println!("Not a numeric!"),
83
+    /// }
84
+    /// ```
85
+    #[inline]
86
+    pub fn new_from_slice(cmd: &'a [u8]) -> Option<Numeric<'a>> {
87
+        if cmd.len() == 3 {
88
+            // TODO switch to TryFrom/TryInto once those are stable. (rust-lang/rust#33417)
89
+            Self::new(array_ref![cmd, 0, 3])
90
+        } else {
91
+            None
92
+        }
93
+    }
94
+
95
+    // not unsafe, but may produce unexpected results
96
+    // keep this private (for now)
97
+    #[inline]
98
+    fn new_unchecked(cmd: &'a [u8; 3]) -> Numeric<'a> {
99
+        Numeric(cmd.iter().map(|x| (x-b'0') as u16).fold(0, |x,y| x*10+y), cmd)
100
+    }
101
+
102
+    /// Returns the numeric as a number, e.g. for processing in code.
103
+    ///
104
+    /// # Examples
105
+    /// ```
106
+    /// use uirc::command::Numeric;
107
+    ///
108
+    /// let numeric = Numeric::new(b"005").unwrap();
109
+    /// match numeric.get_numeric() {
110
+    ///     005 => println!("got an ISUPPORT!"),
111
+    ///     _ => println!("got something else!"),
112
+    /// }
113
+    /// ```
114
+    #[inline]
115
+    pub fn get_numeric(&self) -> u16 {
116
+        self.0
117
+    }
118
+
119
+    /// Returns the numeric as bytes, e.g. for writing to a stream.
120
+    ///
121
+    /// # Examples
122
+    /// ```rust
123
+    /// use uirc::command::Numeric;
124
+    /// use std::io::Write;
125
+    ///
126
+    /// let mut client = Vec::new();
127
+    /// let numeric = Numeric::new(b"005").unwrap();
128
+    /// let bytes = numeric.get_bytes();
129
+    /// client.write_all(bytes).unwrap();
130
+    /// ```
131
+    #[inline]
132
+    pub fn get_bytes(&self) -> &'a [u8; 3] {
133
+        self.1
134
+    }
135
+}
136
+
137
+impl<'a> IrcCommand<'a> {
138
+    pub fn new(cmd: &'a [u8]) -> IrcCommand<'a> {
139
+        if let Some(numeric) = Numeric::new_from_slice(cmd) {
140
+            IrcCommand::Numeric(numeric)
141
+        } else {
142
+            IrcCommand::Stringy(Stringy::new(cmd).unwrap())
143
+        }
144
+    }
145
+}
146
+
147
+impl<'a> fmt::Display for Stringy<'a> {
148
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
149
+        let mut i = 0;
150
+        let l = self.0.len();
151
+        let v = self.0;
152
+        while i < l {
153
+            let st = from_utf8(&v[i..]);
154
+            if let Ok(s) = st {
155
+                write!(f, "{}", s)?;
156
+                break;
157
+            } else {
158
+                let err = st.err().unwrap();
159
+                write!(f, "{}", unsafe { from_utf8_unchecked(&v[i..][..err.valid_up_to()])})?;
160
+                write!(f, "\u{FFFD}")?;
161
+                match err.error_len() {
162
+                    None => i = l,
163
+                    Some(len) => i = i + err.valid_up_to() + len
164
+                }
165
+            }
166
+        }
167
+        Ok(())
168
+    }
169
+}
170
+
171
+impl<'a> fmt::Display for Numeric<'a> {
172
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
173
+        write!(f, "{}", self.0)
174
+    }
175
+}

+ 4
- 0
src/commands.rs View File

@@ -0,0 +1,4 @@
1
+// What was I gonna put here?
2
+//
3
+// I didn't manage to recover this file from the depths of /dev/sdb1, so I don't know what it was
4
+// for.

+ 10
- 0
src/lib.rs View File

@@ -0,0 +1,10 @@
1
+#[macro_use]
2
+extern crate arrayref;
3
+#[macro_use]
4
+extern crate matches;
5
+
6
+pub mod command;
7
+
8
+pub mod commands;
9
+
10
+pub mod simple;

+ 38
- 0
src/simple.rs View File

@@ -0,0 +1,38 @@
1
+use command::{IrcCommand, IrcCommandLine, Numeric, Stringy};
2
+
3
+use std::io;
4
+use std::io::prelude::*;
5
+
6
+use std::ops::Range;
7
+
8
+pub struct SimpleIrcCommand {
9
+    command: Vec<u8>,
10
+    arguments: (Vec<Range<usize>>, Vec<u8>),
11
+    source: Vec<u8>,
12
+}
13
+
14
+impl IrcCommandLine for SimpleIrcCommand {
15
+    fn get_command<'a>(&'a self) -> IrcCommand<'a> {
16
+        IrcCommand::new(&self.command)
17
+    }
18
+
19
+    fn get_argument<'a>(&'a self, arg: usize) -> &'a [u8] {
20
+        &self.arguments.1[self.arguments.0[arg].clone()] // awful API there, rust.
21
+    }
22
+
23
+    fn get_argument_count(&self) -> usize {
24
+        self.arguments.0.len()
25
+    }
26
+
27
+    fn get_source<'a>(&'a self) -> &'a [u8] {
28
+        &self.source
29
+    }
30
+}
31
+
32
+pub struct NoIrcConnection;
33
+
34
+impl NoIrcConnection {
35
+    pub fn read_command<R: Read>(reader: R) -> io::Result<SimpleIrcCommand> {
36
+        unimplemented!()
37
+    }
38
+}

Loading…
Cancel
Save