diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml new file mode 100644 index 0000000..30e34c6 --- /dev/null +++ b/.github/workflows/rust.yml @@ -0,0 +1,208 @@ +name: Rust Overall workflow + +on: [push] + +env: + CARGO_TERM_COLOR: always + +jobs: + build: + runs-on: ubuntu-latest + strategy: + matrix: + rust: + - stable + - nightly + - 1.40.0 + steps: + - uses: actions/checkout@v2 + - name: Loading Cache + uses: actions/cache@v2 + with: + path: | + ~/.cargo/registry + ~/.cargo/git + target + key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}-${{ matrix.rust }} + - name: Install latest toolchain + uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: ${{ matrix.rust }} + override: true + - name: Run cargo build + uses: actions-rs/cargo@v1 + with: + command: build + args: --package irc-rust + check: + runs-on: ubuntu-latest + strategy: + matrix: + rust: + - stable + - nightly + - 1.40.0 + steps: + - uses: actions/checkout@v2 + - name: Loading Cache + uses: actions/cache@v2 + with: + path: | + ~/.cargo/registry + ~/.cargo/git + target + key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}-${{ matrix.rust }} + - name: Install latest stable + uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: ${{ matrix.rust }} + override: true + - name: Run cargo check + uses: actions-rs/cargo@v1 + with: + command: check + args: --package irc-rust + fmt: + runs-on: ubuntu-latest + strategy: + matrix: + rust: + - stable + - nightly + - 1.40.0 + steps: + - uses: actions/checkout@v2 + - name: Loading Cache + uses: actions/cache@v2 + with: + path: | + ~/.cargo/registry + ~/.cargo/git + target + key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}-${{ matrix.rust }} + - name: Install latest stable + uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: ${{ matrix.rust }} + override: true + components: rustfmt + - name: Run cargo fmt + uses: actions-rs/cargo@v1 + with: + command: fmt + args: --all -- --check + clippy: + runs-on: ubuntu-latest + strategy: + matrix: + rust: + - stable + - nightly + - 1.40.0 + steps: + - uses: actions/checkout@v2 + - name: Loading Cache + uses: actions/cache@v2 + with: + path: | + ~/.cargo/registry + ~/.cargo/git + target + key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}-${{ matrix.rust }} + - name: Install latest stable + uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: ${{ matrix.rust }} + override: true + components: clippy + - name: Run cargo clippy + uses: actions-rs/cargo@v1 + with: + command: clippy + args: --package irc-rust -- -D warnings + test: + runs-on: ubuntu-latest + strategy: + matrix: + rust: + - nightly + steps: + - uses: actions/checkout@v2 + - name: Loading Cache + uses: actions/cache@v2 + with: + path: | + ~/.cargo/registry + ~/.cargo/git + target + key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}-${{ matrix.rust }} + - name: Install latest stable + uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: ${{ matrix.rust }} + override: true + - name: Run cargo test + uses: actions-rs/cargo@v1 + with: + command: test + args: --package irc-rust + env: + CARGO_INCREMENTAL: 0 + # '-Cpanic=abort -Zpanic_abort_tests' fails if benchmarks are part of tests + RUSTFLAGS: "-Zprofile -Ccodegen-units=1 -Cinline-threshold=0 -Clink-dead-code -Coverflow-checks=off" + - name: Gather coverage data + id: coverage + uses: actions-rs/grcov@v0.1 + with: + coveralls-token: ${{ secrets.COVERALLS_TOKEN }} + - name: Coveralls upload + uses: coverallsapp/github-action@master + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + parallel: true + path-to-lcov: ${{ steps.coverage.outputs.report }} + grcov_finalize: + runs-on: ubuntu-latest + needs: test + steps: + - name: Coveralls finalization + uses: coverallsapp/github-action@master + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + parallel-finished: true + bench: + # Benchmarks can only run on nightly yet + # Currently fails to extract benchmark information https://github.com/rhysd/github-action-benchmark/issues/39 + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Loading Cache + uses: actions/cache@v2 + with: + path: | + ~/.cargo/registry + ~/.cargo/git + target + key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}-nightly + - name: Install latest nightly + uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: nightly + override: true + - name: Benchmarks + # Currently fails to extract benchmark information https://github.com/rhysd/github-action-benchmark/issues/39 + # Thats why '::' is replaced with ' ' + run: cargo +nightly bench | sed 's/::/__/' | tee output.txt + - name: Store benchmark result + uses: rhysd/github-action-benchmark@v1 + with: + tool: 'cargo' + output-file-path: output.txt + github-token: ${{ secrets.PERSONAL_GITHUB_TOKEN }} + auto-push: true diff --git a/Cargo.toml b/Cargo.toml index 4db7415..0c7ce9e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,22 +1,8 @@ -[package] -name = "irc-rust" -version = "0.3.0" -authors = ["mo_blaa "] -edition = "2018" -description = "IRC Helper easing the access and creation of IRC Messages" -documentation = "https://docs.rs/irc_rust" -homepage = "https://github.com/MoBlaa/irc_rust" -repository = "https://github.com/MoBlaa/irc_rust" -license = "MIT" -readme = "README.md" -keywords = ["irc", "api"] -categories = ["parser-implementations", "encoding"] +[workspace] +members = [ + "lib", + "bench" +] -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -serde = { version = "1.0.111", optional = true, features = ["derive"]} - -[dev-dependencies] -rand = "0.7.3" -serde_json = "1.0.53" +[profile.bench] +lto = true diff --git a/Makefile b/Makefile deleted file mode 100644 index 7021206..0000000 --- a/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -.PHONY: coverage build install_coverage_tool - -build: - @cargo build --release - -install_coverage_tool: - @cargo install cargo-tarpaulin - -coverage: install_coverage_tool - @cargo tarpaulin -v diff --git a/README.md b/README.md index e5ee80c..2685775 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,39 @@ -# irc-rust [![https://docs.rs/irc-rust/badge.svg](https://docs.rs/irc-rust/badge.svg)](https://docs.rs/irc-rust) [![crates.io](https://img.shields.io/crates/v/irc-rust.svg)](https://crates.io/crates/irc-rust) -IRC Helper easing the access and creation of IRC Messages. +# irc-rust [![https://docs.rs/irc-rust/badge.svg](https://docs.rs/irc-rust/badge.svg)](https://docs.rs/irc-rust) [![crates.io](https://img.shields.io/crates/v/irc-rust.svg)](https://crates.io/crates/irc-rust) [![Coverage Status](https://coveralls.io/repos/github/MoBlaa/irc_rust/badge.svg?branch=github-actions)](https://coveralls.io/github/MoBlaa/irc_rust?branch=github-actions) +IRC Helper easing the access and creation of IRC Messages. Minimum supported rust version (MRSV) is **1.40.0**. + +Github-actions runs `build`, `check`, `fmt`, `clippy` and `test` against the latest stable, nightly and 1.40.0 rust toolchains. + +## Installation + +Requirements: + +- [`Install nightly Rust toolchain`](https://www.rust-lang.org/tools/install): +```shell script +curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- --default-toolchain none -y +.rustup.rs | sh +``` + +Installation: + +- Add to `Cargo.toml`: +```toml +[dependencies] +irc-rust = "0.3" +``` +- Or use [`cargo edit`](https://github.com/killercup/cargo-edit) to get the latest every time: +```shell script +cargo install cargo-edit +cargo add irc-rust # In your project root +``` ## Basic Usage ```rust use irc_rust::Message; -let message = Message::from("@key1=value1;key2=value2 :name!user@host CMD param1 param2 :trailing"); - -assert_eq!(message.to_string(), "@key1=value1;key2=value2 :name!user@host CMD param1 param2 :trailing"); +fn main() { + let message = Message::from("@key1=value1;key2=value2 :name!user@host CMD param1 param2 :trailing"); + + assert_eq!(message.to_string(), "@key1=value1;key2=value2 :name!user@host CMD param1 param2 :trailing"); +} ``` diff --git a/bench/Cargo.toml b/bench/Cargo.toml new file mode 100644 index 0000000..4b392d3 --- /dev/null +++ b/bench/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "irc-rust-bench" +version = "0.1.0" +authors = ["moblaa "] +edition = "2018" +description = "Benchmarking project for irc-rust to enable building for stable" +license = "MIT" +repository = "https://github.com/MoBlaa/irc_rust.git" +readme = "../README.md" +keywords = ["benchmarks"] +categories = ["benchmarks"] +publish = false + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +irc-rust = { path = "../lib" } + +[dev-dependencies] +rand = "0.7.3" +serde_json = "1.0.53" diff --git a/src/bench.rs b/bench/src/bench.rs similarity index 97% rename from src/bench.rs rename to bench/src/bench.rs index d507d41..0b4bb78 100644 --- a/src/bench.rs +++ b/bench/src/bench.rs @@ -1,12 +1,10 @@ extern crate rand; extern crate test; -use test::Bencher; - use rand::Rng; +use test::Bencher; -use crate::message::Message; -use crate::{Params, Tags, InvalidIrcFormatError}; +use irc_rust::{InvalidIrcFormatError, Message, Params, Tags}; use std::convert::TryFrom; #[bench] diff --git a/bench/src/lib.rs b/bench/src/lib.rs new file mode 100644 index 0000000..678c187 --- /dev/null +++ b/bench/src/lib.rs @@ -0,0 +1,6 @@ +#![feature(test)] +#![allow(clippy::cargo)] +#![allow(clippy::all)] + +#[cfg(test)] +mod bench; diff --git a/lib/.gitignore b/lib/.gitignore new file mode 100644 index 0000000..92004b0 --- /dev/null +++ b/lib/.gitignore @@ -0,0 +1,27 @@ +# Generated by Cargo +# will have compiled files and executables +/target/ + +# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries +# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html +Cargo.lock + +# These are backup files generated by rustfmt +**/*.rs.bk + + +#Added by cargo + +/target + + +#Added by cargo +# +#already existing elements were commented out + +#/target +#Cargo.lock + +.idea +*.iml +*.iws \ No newline at end of file diff --git a/lib/Cargo.toml b/lib/Cargo.toml new file mode 100644 index 0000000..c48567d --- /dev/null +++ b/lib/Cargo.toml @@ -0,0 +1,22 @@ +[package] +name = "irc-rust" +version = "0.3.0" +authors = ["mo_blaa "] +edition = "2018" +description = "IRC Helper easing the access and creation of IRC Messages" +documentation = "https://docs.rs/irc_rust" +homepage = "https://github.com/MoBlaa/irc_rust" +repository = "https://github.com/MoBlaa/irc_rust" +license = "MIT" +readme = "../README.md" +keywords = ["irc", "api"] +categories = ["parser-implementations", "encoding"] + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +serde = { version = "1.0.111", optional = true, features = ["derive"]} + +[dev-dependencies] +rand = "0.7.3" +serde_json = "1.0.53" diff --git a/LICENSE b/lib/LICENSE similarity index 100% rename from LICENSE rename to lib/LICENSE diff --git a/src/builder.rs b/lib/src/builder.rs similarity index 98% rename from src/builder.rs rename to lib/src/builder.rs index 0cc357a..4138d4a 100644 --- a/src/builder.rs +++ b/lib/src/builder.rs @@ -1,5 +1,5 @@ -use std::collections::HashMap; use crate::MessageBuildError; +use std::collections::HashMap; /// A MessageBuilder for a simpler generation of a message instead of building an string first. #[derive(Debug, Clone, Eq, PartialEq, Default)] @@ -87,9 +87,9 @@ impl<'a> Message<'a> { str.push('@'); for (key, val) in self.tags { str.push_str(key); - str.push_str("="); + str.push('='); str.push_str(val); - str.push_str(";") + str.push(';') } str.pop(); str.push(' '); diff --git a/src/errors.rs b/lib/src/errors.rs similarity index 71% rename from src/errors.rs rename to lib/src/errors.rs index 9e690ba..20e282f 100644 --- a/src/errors.rs +++ b/lib/src/errors.rs @@ -4,14 +4,16 @@ use std::error::Error; #[derive(Debug, Eq, PartialEq, Clone)] pub enum MessageBuildError { UserWithoutHost, - MissingCommand + MissingCommand, } impl fmt::Display for MessageBuildError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let message = match self { - MessageBuildError::UserWithoutHost => "irc prefix can only contain a user if host is also present", - MessageBuildError::MissingCommand => "irc message requires an command" + MessageBuildError::UserWithoutHost => { + "irc prefix can only contain a user if host is also present" + } + MessageBuildError::MissingCommand => "irc message requires an command", }; write!(f, "{}", message) @@ -23,14 +25,18 @@ impl Error for MessageBuildError {} #[derive(Debug, Eq, PartialEq, Clone)] pub enum InvalidIrcFormatError { Tag(String), - NoTagEnd(String) + NoTagEnd(String), } impl fmt::Display for InvalidIrcFormatError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { InvalidIrcFormatError::Tag(raw) => write!(f, "Invalid tags format: {}", raw), - InvalidIrcFormatError::NoTagEnd(raw_message) => write!(f, "No space to end the Tag found in message: {}", raw_message) + InvalidIrcFormatError::NoTagEnd(raw_message) => write!( + f, + "No space to end the Tag found in message: {}", + raw_message + ), } } } diff --git a/src/lib.rs b/lib/src/lib.rs similarity index 95% rename from src/lib.rs rename to lib/src/lib.rs index 20f0204..afa128d 100644 --- a/src/lib.rs +++ b/lib/src/lib.rs @@ -1,4 +1,3 @@ -#![feature(test)] #![deny(clippy::all)] #![deny(clippy::cargo)] @@ -63,22 +62,19 @@ #[macro_use] extern crate serde; -mod message; mod builder; -mod tags; -mod prefix; -mod params; mod errors; +mod message; +mod params; +mod prefix; +mod tags; #[cfg(test)] mod test; -#[cfg(test)] -mod bench; - -pub use message::Message; pub use builder::Message as MessageBuilder; -pub use tags::Tags; -pub use prefix::Prefix; +pub use errors::{InvalidIrcFormatError, MessageBuildError}; +pub use message::Message; pub use params::Params; -pub use errors::{MessageBuildError, InvalidIrcFormatError}; +pub use prefix::Prefix; +pub use tags::Tags; diff --git a/src/message.rs b/lib/src/message.rs similarity index 87% rename from src/message.rs rename to lib/src/message.rs index d046a52..45d872d 100644 --- a/src/message.rs +++ b/lib/src/message.rs @@ -1,11 +1,11 @@ -use std::fmt::{Display, Formatter}; use std::fmt; +use std::fmt::{Display, Formatter}; +use crate::builder::Message as MessageBuilder; +use crate::errors::InvalidIrcFormatError; use crate::params::Params; use crate::prefix::Prefix; use crate::tags::Tags; -use crate::builder::Message as MessageBuilder; -use crate::errors::InvalidIrcFormatError; use std::convert::TryFrom; /// A simple irc message containing tags, prefix, command, parameters and a trailing parameter. @@ -72,7 +72,7 @@ use std::convert::TryFrom; #[derive(Debug, Clone, Eq, Ord, PartialOrd, PartialEq, Hash)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct Message { - raw: String + raw: String, } impl Message { @@ -117,8 +117,7 @@ impl Message { if self.raw.starts_with('@') { let end = self.raw.find(' '); if let Some(end) = end { - Tags::try_from(&self.raw[1..end]) - .map(Some) + Tags::try_from(&self.raw[1..end]).map(Some) } else { Err(InvalidIrcFormatError::NoTagEnd(self.raw.clone())) } @@ -129,20 +128,20 @@ impl Message { /// Returns the Prefix if present. pub fn prefix(&self) -> Result, InvalidIrcFormatError> { - let offset = self.tags() + let offset = self + .tags() // Set offset if tags exist .map(|tags| { // + '@' + ' ' tags.map(|tags| tags.len_raw() + 2) - })?.unwrap_or(0); + })? + .unwrap_or(0); Ok(match self.raw.chars().nth(offset) { - Some(':') => { - match self.raw[offset..].find(' ') { - Some(index) => Some(Prefix::from(&self.raw[offset + 1..offset + index])), - None => Some(Prefix::from(&self.raw[offset + 1..])) - } - } - _ => None + Some(':') => match self.raw[offset..].find(' ') { + Some(index) => Some(Prefix::from(&self.raw[offset + 1..offset + index])), + None => Some(Prefix::from(&self.raw[offset + 1..])), + }, + _ => None, }) } @@ -156,7 +155,7 @@ impl Message { &self.raw } } - None => &self.raw + None => &self.raw, }; let without_prefix = match without_tags.find(' ') { Some(start) => { @@ -166,11 +165,11 @@ impl Message { without_tags } } - None => &self.raw + None => &self.raw, }; match without_prefix.find(' ') { Some(end) => &without_prefix[..end], - None => without_prefix + None => without_prefix, } } @@ -178,7 +177,8 @@ impl Message { pub fn params(&self) -> Option { let command = self.command(); let cmd_start = self.raw.find(command).unwrap(); - self.raw[cmd_start..].find(' ') + self.raw[cmd_start..] + .find(' ') .map(|param_start| Params::from(&self.raw[cmd_start + param_start..])) } } @@ -191,16 +191,14 @@ impl Display for Message { impl From for Message { fn from(raw: String) -> Self { - Message { - raw - } + Message { raw } } } impl From<&str> for Message { fn from(raw: &str) -> Self { Message { - raw: raw.to_string() + raw: raw.to_string(), } } } @@ -212,7 +210,8 @@ mod tests { #[test] #[cfg(feature = "serde")] fn test_serde() { - let message = Message::from("@test=test :user@prefix!host COMMAND param :trailing".to_string()); + let message = + Message::from("@test=test :user@prefix!host COMMAND param :trailing".to_string()); let serialized = serde_json::to_string(&message).unwrap(); println!("Ser: {}", serialized); let deserialized: Message = serde_json::from_str(serialized.as_str()).unwrap(); @@ -221,7 +220,8 @@ mod tests { #[test] fn test_tags() { - let message = Message::from("@test=test :user@prefix!host COMMAND param :trailing".to_string()); + let message = + Message::from("@test=test :user@prefix!host COMMAND param :trailing".to_string()); let tags = message.tags(); assert!(tags.is_ok(), "{:?}", tags); let tags = tags.unwrap(); @@ -230,7 +230,8 @@ mod tests { #[test] fn test_prefix() { - let message = Message::from("@test=test :user@prefix!host COMMAND param :trailing".to_string()); + let message = + Message::from("@test=test :user@prefix!host COMMAND param :trailing".to_string()); let prefix = message.prefix(); assert!(prefix.is_ok(), "{:?}", prefix); let prefix = prefix.unwrap(); diff --git a/src/params.rs b/lib/src/params.rs similarity index 86% rename from src/params.rs rename to lib/src/params.rs index 07bb97e..1c3dca8 100644 --- a/src/params.rs +++ b/lib/src/params.rs @@ -5,7 +5,7 @@ use core::fmt; #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct Params<'a> { raw: &'a str, - trailing_start: Option + trailing_start: Option, } impl<'a> Params<'a> { @@ -13,15 +13,14 @@ impl<'a> Params<'a> { pub fn new() -> Params<'a> { Params { raw: "", - trailing_start: None + trailing_start: None, } } /// Returns the trailing parameter which is seperated from the /// other parameters with ' :'. pub fn trailing(&self) -> Option<&'a str> { - self.trailing_start - .map(|index| &self.raw[index + 2..]) + self.trailing_start.map(|index| &self.raw[index + 2..]) } /// Create an iterator over the parameter list excluding the trailing parameter. @@ -30,7 +29,7 @@ impl<'a> Params<'a> { // Split into parameter list and trailing Some(index) => self.raw[..index].split_whitespace(), // Only split parameters - None => self.raw.split_whitespace() + None => self.raw.split_whitespace(), } } } @@ -47,7 +46,7 @@ impl<'a> From<&'a str> for Params<'a> { Params { raw, - trailing_start + trailing_start, } } } diff --git a/src/prefix.rs b/lib/src/prefix.rs similarity index 78% rename from src/prefix.rs rename to lib/src/prefix.rs index e19cdc9..88e09db 100644 --- a/src/prefix.rs +++ b/lib/src/prefix.rs @@ -6,20 +6,20 @@ use std::fmt; #[derive(Debug, Clone, Copy, Eq, Ord, PartialOrd, PartialEq, Hash, Default)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct Prefix<'a> { - raw: &'a str + raw: &'a str, } impl<'a> Prefix<'a> { /// Create a new Prefix from the given string. Expects the string to be a valid prefix string. pub fn new() -> Self { - Prefix { - raw: "" - } + Prefix { raw: "" } } // Returns the (server- or nick-) name. pub fn name(&self) -> &'a str { - let end = self.raw.find('!') + let end = self + .raw + .find('!') .or_else(|| self.raw.find('@')) .or_else(|| self.raw.find(' ')) .unwrap_or_else(|| self.raw.len()); @@ -33,20 +33,16 @@ impl<'a> Prefix<'a> { // Returns the host if present. pub fn user(&self) -> Option<&'a str> { - self.raw.find('!') - .map(|start| { - let end = self.raw.find('@') - .unwrap_or_else(|| self.raw.len()); - &self.raw[start + 1..end] - }) + self.raw.find('!').map(|start| { + let end = self.raw.find('@').unwrap_or_else(|| self.raw.len()); + &self.raw[start + 1..end] + }) } } impl<'a> From<&'a str> for Prefix<'a> { fn from(raw: &'a str) -> Self { - Prefix { - raw - } + Prefix { raw } } } diff --git a/src/tags.rs b/lib/src/tags.rs similarity index 86% rename from src/tags.rs rename to lib/src/tags.rs index 92efcda..88c85ab 100644 --- a/src/tags.rs +++ b/lib/src/tags.rs @@ -1,8 +1,8 @@ -use std::ops::Index; +use crate::errors::InvalidIrcFormatError; use core::fmt; use std::collections::HashMap; -use crate::errors::InvalidIrcFormatError; use std::convert::TryFrom; +use std::ops::Index; /// Tag Map as described through IRCv3. /// @@ -38,23 +38,22 @@ impl<'a> Tags<'a> { } /// Iterator over the tag entries. - pub fn iter(&self) -> impl Iterator { - self.raw.split(';') - .map(|kv| { - let mut split = kv.split('='); - (split.next().unwrap(), split.next().unwrap()) - }) + pub fn iter(&self) -> impl Iterator { + self.raw.split(';').map(|kv| { + let mut split = kv.split('='); + (split.next().unwrap(), split.next().unwrap()) + }) } // Search for the key and return start and end of the value fn find(&self, key: &'a str) -> Option<(usize, usize)> { let key_equals = format!("{}=", key); - self.raw.find(&key_equals) - .map(|start| { - start + key.len() + 1 - }) + self.raw + .find(&key_equals) + .map(|start| start + key.len() + 1) .and_then(|start| { - self.raw[start..].find(';') + self.raw[start..] + .find(';') .or_else(|| self.raw[start..].find(' ')) .or_else(|| Some(self.raw.len() - start)) .map(|end| (start, start + end)) @@ -62,12 +61,10 @@ impl<'a> Tags<'a> { } pub fn get(&self, key: &'a str) -> Option<&'a str> { - self.find(key) - .map(|(start, end)| &self.raw[start..end]) + self.find(key).map(|(start, end)| &self.raw[start..end]) } } - impl<'a> TryFrom<&'a str> for Tags<'a> { type Error = InvalidIrcFormatError; @@ -82,11 +79,11 @@ impl<'a> TryFrom<&'a str> for Tags<'a> { let mut split = key_val.split('='); let key = match split.next() { Some(key) => key, - None => return Err(InvalidIrcFormatError::Tag(raw.to_string())) + None => return Err(InvalidIrcFormatError::Tag(raw.to_string())), }; let value = match split.next() { Some(value) => value, - None => return Err(InvalidIrcFormatError::Tag(raw.to_string())) + None => return Err(InvalidIrcFormatError::Tag(raw.to_string())), }; if split.next().is_some() { return Err(InvalidIrcFormatError::Tag(raw.to_string())); @@ -94,10 +91,7 @@ impl<'a> TryFrom<&'a str> for Tags<'a> { tags.insert(key, value); } tags.shrink_to_fit(); - Ok(Tags { - raw, - tags, - }) + Ok(Tags { raw, tags }) } } @@ -124,8 +118,8 @@ impl<'a> AsRef for Tags<'a> { #[cfg(test)] mod tests { use crate::tags::Tags; - use std::convert::TryFrom; use crate::InvalidIrcFormatError; + use std::convert::TryFrom; #[test] fn test_get_and_index() -> Result<(), InvalidIrcFormatError> { diff --git a/src/test.rs b/lib/src/test.rs similarity index 90% rename from src/test.rs rename to lib/src/test.rs index 7d0a1b8..6d1fafd 100644 --- a/src/test.rs +++ b/lib/src/test.rs @@ -3,9 +3,13 @@ use crate::InvalidIrcFormatError; #[test] fn test_parse() { - let message = Message::from("@key1=value1;key2=value2 :name!user@host CMD param1 param2 :trailing"); + let message = + Message::from("@key1=value1;key2=value2 :name!user@host CMD param1 param2 :trailing"); - assert_eq!(message.to_string(), "@key1=value1;key2=value2 :name!user@host CMD param1 param2 :trailing"); + assert_eq!( + message.to_string(), + "@key1=value1;key2=value2 :name!user@host CMD param1 param2 :trailing" + ); let tags = message.tags().unwrap().unwrap(); let val = &tags["key1"]; @@ -184,14 +188,20 @@ fn test_message_builder() -> Result<(), InvalidIrcFormatError> { .prefix_user("user") .prefix_host("host") .command("CMD") - .param("param1").param("param2") + .param("param1") + .param("param2") .trailing("trailing") .build() .expect("failed to build message"); let str = message.to_string(); - assert!(str.as_str() == "@key1=value1;key2=value2 :name!user@host CMD param1 param2 :trailing" || str.as_str() == "@key2=value2;key1=value1 :name!user@host CMD param1 param2 :trailing"); - - let message = message.to_builder()? + assert!( + str.as_str() == "@key1=value1;key2=value2 :name!user@host CMD param1 param2 :trailing" + || str.as_str() + == "@key2=value2;key1=value1 :name!user@host CMD param1 param2 :trailing" + ); + + let message = message + .to_builder()? .tag("key1", "value3") .prefix_name("name1") .param("param2")