Add documentation

This commit is contained in:
Ethan Henderson 2022-07-30 15:06:05 +01:00
parent d7e6b99c30
commit 22ee36471d
3 changed files with 182 additions and 0 deletions

View file

@ -1,3 +1,53 @@
# ircparser # ircparser
An IRC (RFC1459) parser and formatter, built in Rust. An IRC (RFC1459) parser and formatter, built in Rust.
## Setup
To use the latest stable version of `ircparser`, add it to your Cargo.toml file like so:
```toml
[dependencies]
ircparser = "^0.1"
```
You can also use the latest development version by specifying the following:
```toml
[dependencies]
ircparser = { git = "https://github.com/parafoxia/ircparser" }
```
## Usage
`ircparser` currently only has one public function — `parse`.
This function takes a line of an IRC message, and parses it into an easy-to-use `Line` object.
```rs
use ircparser;
fn main() {
let msg = "@id=123;name=rick :nick!user@host.tmi.twitch.tv PRIVMSG #rickastley :Never gonna give you up!";
match ircparser::parse(msg) {
Ok(x) => {
let line = x;
assert_eq!(&line.tags["id"], "123");
if line.source.is_some() {
assert_eq!(line.source.unwrap(), ":nick!user@host.tmi.twitch.tv");
}
assert_eq!(line.command, "PRIVMSG");
assert_eq!(line.params[0], "#rickastley");
assert_eq!(line.params[1], "Never gonna give you up!");
}
Err(e) => {
println!("A parsing error occured: {e}");
return;
}
};
}
```
## License
The `ircparser` crate for Rust is licensed under the [BSD 3-Clause License](https://github.com/parafoxia/ircparser/blob/main/LICENSE).

View file

@ -28,6 +28,35 @@
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//! An IRC (RFC1459) parser and formatter, built in Rust.
//!
//! ## Parsing messages
//!
//! You can parse IRC messages using the provided `parse` function.
//!
//! ```
//! fn main() {
//! let msg = "@id=123;name=rick :nick!user@host.tmi.twitch.tv PRIVMSG #rickastley :Never gonna give you up!";
//! match ircparser::parse(msg) {
//! Ok(x) => {
//! let line = x;
//!
//! assert_eq!(&line.tags["id"], "123");
//! if line.source.is_some() {
//! assert_eq!(line.source.unwrap(), ":nick!user@host.tmi.twitch.tv");
//! }
//! assert_eq!(line.command, "PRIVMSG");
//! assert_eq!(line.params[0], "#rickastley");
//! assert_eq!(line.params[1], "Never gonna give you up!");
//! }
//! Err(e) => {
//! println!("A parsing error occured: {e}");
//! return;
//! }
//! };
//! }
//! ```
mod line; mod line;
pub use line::Line; pub use line::Line;
@ -35,12 +64,25 @@ use std::collections::HashMap;
type ParseResult<T> = Result<T, ParseError>; type ParseResult<T> = Result<T, ParseError>;
/// Exception thrown when an error occurs during message parsing.
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct ParseError { pub struct ParseError {
/// The details of this error.
pub details: String, pub details: String,
} }
impl ParseError { impl ParseError {
/// Generates a new [`ParseError`].
///
/// # Arguments
/// - `details` - THe details of this error.
///
/// # Example
/// ```
/// let e = ircparser::ParseError::new("err");
///
/// assert_eq!(e.details, "err".to_string())
/// ```
pub fn new(details: &str) -> Self { pub fn new(details: &str) -> Self {
Self { Self {
details: details.into(), details: details.into(),
@ -64,6 +106,35 @@ fn find_index(text: &str, char: char, start: usize) -> Option<usize> {
None None
} }
/// Parses an IRC message.
///
/// # Arguments
/// - `line` - The line you want to parse.
///
/// # Returns
/// - [`Line`] - An instance representing a parsed line.
///
/// # Example
/// ```
/// let msg = "@id=123;name=rick :nick!user@host.tmi.twitch.tv PRIVMSG #rickastley :Never gonna give you up!";
/// match ircparser::parse(msg) {
/// Ok(x) => {
/// let line = x;
///
/// assert_eq!(&line.tags["id"], "123");
/// if line.source.is_some() {
/// assert_eq!(line.source.unwrap(), ":nick!user@host.tmi.twitch.tv");
/// }
/// assert_eq!(line.command, "PRIVMSG");
/// assert_eq!(line.params[0], "#rickastley");
/// assert_eq!(line.params[1], "Never gonna give you up!");
/// }
/// Err(e) => {
/// println!("A parsing error occured: {e}");
/// return;
/// }
/// };
/// ```
pub fn parse(line: &str) -> ParseResult<Line> { pub fn parse(line: &str) -> ParseResult<Line> {
if line.is_empty() { if line.is_empty() {
return Err(ParseError::new("line length cannot be 0")); return Err(ParseError::new("line length cannot be 0"));
@ -143,4 +214,26 @@ mod test_lib {
assert_eq!(line.command, "PRIVMSG"); assert_eq!(line.command, "PRIVMSG");
assert_eq!(line.params, vec!["#rickastley", "Never gonna give you up!"]); assert_eq!(line.params, vec!["#rickastley", "Never gonna give you up!"]);
} }
#[test]
fn test_readme_example() {
let msg = "@id=123;name=rick :nick!user@host.tmi.twitch.tv PRIVMSG #rickastley :Never gonna give you up!";
match parse(msg) {
Ok(x) => {
let line = x;
assert_eq!(&line.tags["id"], "123");
if line.source.is_some() {
assert_eq!(line.source.unwrap(), ":nick!user@host.tmi.twitch.tv");
}
assert_eq!(line.command, "PRIVMSG");
assert_eq!(line.params[0], "#rickastley");
assert_eq!(line.params[1], "Never gonna give you up!");
}
Err(e) => {
println!("A parsing error occured: {e}");
return;
}
};
}
} }

View file

@ -30,15 +30,54 @@
use std::collections::HashMap; use std::collections::HashMap;
/// A struct representing a parsed line.
#[derive(Debug, Clone, Default)] #[derive(Debug, Clone, Default)]
pub struct Line { pub struct Line {
/// This line's tags. This will be an empty hashmap if there are
/// none.
pub tags: HashMap<String, String>, pub tags: HashMap<String, String>,
/// This line's source (including the nick, user, and host). This is
/// optional, and will be [`None`] if not provided.
pub source: Option<String>, pub source: Option<String>,
/// This line's command.
pub command: String, pub command: String,
/// Any parameters passed to the command. This will be an empty
/// vector if there are none.
pub params: Vec<String>, pub params: Vec<String>,
} }
impl Line { impl Line {
/// Creates a new [`Line`]. You should never call this directly, but
/// instead use the [ircparser::parse](super::parse) function.
///
/// # Arguments
/// - `tags` - This line's tags.
/// = `source` - This line's source, or [`None`] if not to be
/// provided.
/// - `command` - This line's command.
/// - `params` - Any parameters passed to the command.
///
/// # Returns
/// - [`Line`] - The new [`Line`] instance.
///
/// # Example
/// ```
/// use std::collections::HashMap;
///
/// let mut tags: HashMap<String, String> = HashMap::new();
/// tags.insert("id".to_string(), "123".to_string());
///
/// let source = Some(":nick!user@host.tmi.twitch.tv".to_string());
/// let command = "PRIVMSG";
/// let params = vec!["#rickastley".to_string()];
///
/// let line = ircparser::Line::new(tags, source, command, params);
///
/// assert_eq!(&line.tags["id"], "123");
/// assert_eq!(line.source.unwrap(), ":nick!user@host.tmi.twitch.tv");
/// assert_eq!(line.command, "PRIVMSG");
/// assert_eq!(line.params[0], "#rickastley");
/// ```
pub fn new( pub fn new(
tags: HashMap<String, String>, tags: HashMap<String, String>,
source: Option<String>, source: Option<String>,