diff --git a/Cargo.toml b/Cargo.toml index f10f3cc..6e8c53a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,7 +11,3 @@ readme = "README.md" keywords = ["ids", "encode", "short", "sqids", "hashids"] [dependencies] -derive_builder = "0.20.2" -serde = "1.0.217" -serde_json = "1.0.134" -thiserror = "2.0.9" diff --git a/src/lib.rs b/src/lib.rs index 8dac92c..a5c566c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,13 +10,10 @@ /// **Note**: This is the crate's license and not an actual item. pub const LICENSE: () = (); -use std::{cmp::min, collections::HashSet, result}; - -use derive_builder::Builder; -use thiserror::Error; +use std::{cmp::min, collections::HashSet, fmt, result}; /// sqids Error type. -#[derive(Error, Debug, Eq, PartialEq)] +#[derive(Debug, Eq, PartialEq)] pub enum Error { /// Alphabet cannot contain multibyte characters /// @@ -25,7 +22,6 @@ pub enum Error { /// let error = Sqids::builder().alphabet("☃️🦀🔥".chars().collect()).build().unwrap_err(); /// assert_eq!(error, Error::AlphabetMultibyteCharacters); /// ``` - #[error("Alphabet cannot contain multibyte characters")] AlphabetMultibyteCharacters, /// Alphabet length must be at least 3 /// @@ -34,7 +30,6 @@ pub enum Error { /// let error = Sqids::builder().alphabet("ab".chars().collect()).build().unwrap_err(); /// assert_eq!(error, Error::AlphabetLength); /// ``` - #[error("Alphabet length must be at least 3")] AlphabetLength, /// Alphabet must contain unique characters /// @@ -43,7 +38,6 @@ pub enum Error { /// let error = Sqids::builder().alphabet("aba".chars().collect()).build().unwrap_err(); /// assert_eq!(error, Error::AlphabetUniqueCharacters); /// ``` - #[error("Alphabet must contain unique characters")] AlphabetUniqueCharacters, /// Reached max attempts to re-generate the ID /// @@ -58,10 +52,28 @@ pub enum Error { /// let error = sqids.encode(&[1]).unwrap_err(); /// assert_eq!(error, Error::BlocklistMaxAttempts); /// ``` - #[error("Reached max attempts to re-generate the ID")] BlocklistMaxAttempts, } +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Error::AlphabetMultibyteCharacters => { + f.write_str("Alphabet cannot contain multibyte characters") + } + Error::AlphabetLength => f.write_str("Alphabet length must be at least 3"), + Error::AlphabetUniqueCharacters => { + f.write_str("Alphabet must contain unique characters") + } + Error::BlocklistMaxAttempts => { + f.write_str("Reached max attempts to re-generate the ID") + } + } + } +} + +impl std::error::Error for Error {} + /// type alias for Result pub type Result = result::Result; @@ -70,7 +82,8 @@ pub const DEFAULT_ALPHABET: &str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQR /// Returns the default blocklist when none is given when creating a [Sqids]. pub fn default_blocklist() -> HashSet { - serde_json::from_str(include_str!("blocklist.json")).unwrap() + const DEFAULT_BLOCKLIST: &[&str] = &include!("blocklist.json"); + DEFAULT_BLOCKLIST.iter().map(|&s| s.to_owned()).collect() } /// Options for creating a [Sqids]. @@ -119,15 +132,10 @@ impl Default for Options { } /// A generator for sqids. -#[derive(Clone, Debug, Builder)] -#[builder(build_fn(skip, error = "Error"), pattern = "owned")] +#[derive(Clone, Debug)] pub struct Sqids { - /// The alphabet that is being used when generating sqids. alphabet: Vec, - /// The minimum length of a sqid. min_length: u8, - /// Blocklist. When creating a sqid strings that begins - /// with one of these will be avoided. blocklist: HashSet, } @@ -137,12 +145,36 @@ impl Default for Sqids { } } +/// Builder for [`Sqids`]. +#[derive(Default)] +pub struct SqidsBuilder { + alphabet: Option>, + min_length: u8, + blocklist: Option>, +} + impl SqidsBuilder { /// Create a [SqidsBuilder]. pub fn new() -> Self { Self::default() } + /// The alphabet that is being used when generating sqids. + pub fn alphabet(self, value: Vec) -> Self { + Self { alphabet: Some(value), ..self } + } + + /// The minimum length of a sqid. + pub fn min_length(self, value: u8) -> Self { + Self { min_length: value, ..self } + } + + /// Blocklist. When creating a sqid strings that begins + /// with one of these will be avoided. + pub fn blocklist(self, value: HashSet) -> Self { + Self { blocklist: Some(value), ..self } + } + /// Build a [Sqids] object. pub fn build(self) -> Result { let alphabet: Vec = @@ -181,7 +213,7 @@ impl SqidsBuilder { Ok(Sqids { alphabet: Sqids::shuffle(&alphabet), - min_length: self.min_length.unwrap_or(0), + min_length: self.min_length, blocklist: filtered_blocklist, }) }