diff --git a/Cargo.lock b/Cargo.lock index 1002174..6d0beb1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -862,6 +862,12 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "maplit" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d" + [[package]] name = "matches" version = "0.1.9" @@ -1047,6 +1053,7 @@ dependencies = [ "format-bytes", "futures", "log", + "maplit", "nom", "panorama-proto-common", "stderrlog", diff --git a/README.md b/README.md index 23bcee1..2da2bc2 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,6 @@ panorama ======== -[![](https://tokei.rs/b1/github/iptq/panorama?category=code)](https://github.com/XAMPPRocky/tokei) - Panorama is a terminal Personal Information Manager (PIM). Status: **still writing the basics** diff --git a/imap/Cargo.toml b/imap/Cargo.toml index 098f1a8..34e072d 100644 --- a/imap/Cargo.toml +++ b/imap/Cargo.toml @@ -42,3 +42,6 @@ panorama-proto-common = { path = "../proto-common" } # for fuzzing arbitrary = { version = "1.0.2", optional = true, features = ["derive"] } + +[dev-dependencies] +maplit = "1.0.2" diff --git a/imap/src/lib.rs b/imap/src/lib.rs index 3e7d0f1..0d2dee1 100644 --- a/imap/src/lib.rs +++ b/imap/src/lib.rs @@ -15,6 +15,9 @@ extern crate log; #[macro_use] extern crate panorama_proto_common; +#[cfg(test)] +#[macro_use] +extern crate maplit; + pub mod client; -// pub mod events; pub mod proto; diff --git a/imap/src/proto/command.rs b/imap/src/proto/command.rs index 882df30..f11047f 100644 --- a/imap/src/proto/command.rs +++ b/imap/src/proto/command.rs @@ -1,4 +1,8 @@ -use std::{collections::HashSet, io::{self, Write}, ops::{Bound, RangeBounds}}; +use std::{ + collections::HashSet, + io::{self, Write}, + ops::{Bound, RangeBounds}, +}; use format_bytes::DisplayBytes; use panorama_proto_common::{quote_string, Bytes}; @@ -175,15 +179,15 @@ impl DisplayBytes for FetchItems { #[derive(Clone, Debug)] pub enum FetchAttr {} -// TODO: not the most efficient representation but I'll optimize if this ever actually becomes a -// problem +// TODO: not the most efficient representation but I'll optimize if this ever +// actually becomes a problem #[derive(Clone, Debug)] -pub struct SearchCriteria(HashSet<(Bound, Bound)>); +pub struct SearchCriteria(Vec<(Bound, Bound)>); impl SearchCriteria { pub fn all() -> Self { - let mut set = HashSet::new(); - set.insert((Bound::Unbounded, Bound::Unbounded)); + let mut set = Vec::new(); + set.push((Bound::Unbounded, Bound::Unbounded)); SearchCriteria(set) } @@ -196,6 +200,12 @@ impl SearchCriteria { false } + + pub fn with_range(&mut self, range: impl RangeBounds) -> &mut Self { + let range = (range.start_bound().cloned(), range.end_bound().cloned()); + self.0.push(range); + self + } } impl DisplayBytes for SearchCriteria { @@ -209,7 +219,7 @@ impl DisplayBytes for SearchCriteria { match range.0 { Bound::Excluded(n) => write_bytes!(w, b"{}", &(n + 1))?, Bound::Included(n) => write_bytes!(w, b"{}", &n)?, - Bound::Unbounded => write_bytes!(w, b"*")?, + Bound::Unbounded => write_bytes!(w, b"1")?, } write_bytes!(w, b":")?; @@ -232,6 +242,17 @@ mod tests { #[test] fn display_search_criteria() { // TODO: is there a trivial case? - assert_eq!(format_bytes!(b"{}", SearchCriteria::all()), b"*:*"); + assert_eq!(format_bytes!(b"{}", SearchCriteria::all()), b"1:*"); + + assert_eq!( + format_bytes!( + b"{}", + SearchCriteria(vec![ + (Bound::Unbounded, Bound::Included(4)), + (Bound::Excluded(5), Bound::Unbounded), + ]) + ), + b"1:4,6:*" + ); } }