mirror of
https://github.com/sqids/sqids-rust
synced 2024-11-23 03:08:36 +00:00
wip
This commit is contained in:
parent
f2d11a023e
commit
cf377536d0
1
.clippy.toml
Normal file
1
.clippy.toml
Normal file
@ -0,0 +1 @@
|
||||
too-many-arguments-threshold = 10
|
1
.gitattributes
vendored
1
.gitattributes
vendored
@ -1 +1,2 @@
|
||||
**/blocklist.json binary
|
||||
Cargo.lock binary
|
@ -1,5 +1,7 @@
|
||||
# [Sqids Rust](https://sqids.org/rust)
|
||||
|
||||
[![Github Actions](https://img.shields.io/github/actions/workflow/status/sqids/sqids-rust/tests.yml)](https://github.com/sqids/sqids-rust/actions)
|
||||
|
||||
Sqids (pronounced "squids") is a small library that lets you generate YouTube-looking IDs from numbers. It's good for link shortening, fast & URL-safe ID generation and decoding back into numbers for quicker database lookups.
|
||||
|
||||
## Getting started
|
||||
|
2
release.toml
Normal file
2
release.toml
Normal file
@ -0,0 +1,2 @@
|
||||
consolidate-commits = false
|
||||
consolidate-pushes = true
|
13
rustfmt.toml
Normal file
13
rustfmt.toml
Normal file
@ -0,0 +1,13 @@
|
||||
max_width = 100
|
||||
comment_width = 100
|
||||
hard_tabs = true
|
||||
edition = "2021"
|
||||
reorder_imports = true
|
||||
imports_granularity = "Crate"
|
||||
use_small_heuristics = "Max"
|
||||
wrap_comments = true
|
||||
binop_separator = "Back"
|
||||
trailing_comma = "Vertical"
|
||||
trailing_semicolon = true
|
||||
use_field_init_shorthand = true
|
||||
format_macro_bodies = true
|
53
src/lib.rs
53
src/lib.rs
@ -1,6 +1,5 @@
|
||||
use derive_more::Display;
|
||||
use std::collections::HashSet;
|
||||
use std::result;
|
||||
use std::{collections::HashSet, result};
|
||||
|
||||
#[derive(Display, Debug)]
|
||||
pub enum Error {
|
||||
@ -18,6 +17,10 @@ pub enum Error {
|
||||
|
||||
pub type Result<T> = result::Result<T, Error>;
|
||||
|
||||
pub fn default_blocklist() -> HashSet<String> {
|
||||
serde_json::from_str(include_str!("blocklist.json")).unwrap()
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Options {
|
||||
alphabet: String,
|
||||
@ -52,7 +55,7 @@ impl Default for Options {
|
||||
Options {
|
||||
alphabet: "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789".to_string(),
|
||||
min_length: 0,
|
||||
blocklist: serde_json::from_str(include_str!("blocklist.json")).unwrap(),
|
||||
blocklist: default_blocklist(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -91,14 +94,11 @@ impl Sqids {
|
||||
})
|
||||
.collect();
|
||||
|
||||
let mut sqids = Sqids {
|
||||
alphabet,
|
||||
min_length: options.min_length,
|
||||
blocklist: filtered_blocklist,
|
||||
};
|
||||
let mut sqids =
|
||||
Sqids { alphabet, min_length: options.min_length, blocklist: filtered_blocklist };
|
||||
|
||||
if options.min_length < sqids.min_value() as usize
|
||||
|| options.min_length > options.alphabet.len()
|
||||
if options.min_length < sqids.min_value() as usize ||
|
||||
options.min_length > options.alphabet.len()
|
||||
{
|
||||
return Err(Error::MinLength {
|
||||
min: sqids.min_value() as usize,
|
||||
@ -122,10 +122,7 @@ impl Sqids {
|
||||
.collect();
|
||||
|
||||
if in_range_numbers.len() != numbers.len() {
|
||||
return Err(Error::EncodingRange {
|
||||
min: self.min_value(),
|
||||
max: self.max_value(),
|
||||
});
|
||||
return Err(Error::EncodingRange { min: self.min_value(), max: self.max_value() });
|
||||
}
|
||||
|
||||
self.encode_numbers(&in_range_numbers, false)
|
||||
@ -145,14 +142,8 @@ impl Sqids {
|
||||
|
||||
let prefix = id.chars().next().unwrap();
|
||||
let offset = self.alphabet.iter().position(|&c| c == prefix).unwrap();
|
||||
let mut alphabet: Vec<char> = self
|
||||
.alphabet
|
||||
.iter()
|
||||
.cycle()
|
||||
.skip(offset)
|
||||
.take(self.alphabet.len())
|
||||
.copied()
|
||||
.collect();
|
||||
let mut alphabet: Vec<char> =
|
||||
self.alphabet.iter().cycle().skip(offset).take(self.alphabet.len()).copied().collect();
|
||||
|
||||
let partition = alphabet[1];
|
||||
|
||||
@ -199,22 +190,12 @@ impl Sqids {
|
||||
}
|
||||
|
||||
fn encode_numbers(&self, numbers: &[u64], partitioned: bool) -> Result<String> {
|
||||
let offset = numbers
|
||||
.iter()
|
||||
.enumerate()
|
||||
.fold(numbers.len(), |a, (i, &v)| {
|
||||
let offset = numbers.iter().enumerate().fold(numbers.len(), |a, (i, &v)| {
|
||||
self.alphabet[v as usize % self.alphabet.len()] as usize + i + a
|
||||
})
|
||||
% self.alphabet.len();
|
||||
}) % self.alphabet.len();
|
||||
|
||||
let mut alphabet: Vec<char> = self
|
||||
.alphabet
|
||||
.iter()
|
||||
.cycle()
|
||||
.skip(offset)
|
||||
.take(self.alphabet.len())
|
||||
.copied()
|
||||
.collect();
|
||||
let mut alphabet: Vec<char> =
|
||||
self.alphabet.iter().cycle().skip(offset).take(self.alphabet.len()).copied().collect();
|
||||
|
||||
let prefix = alphabet[0];
|
||||
let partition = alphabet[1];
|
||||
|
@ -2,10 +2,128 @@ use sqids::*;
|
||||
|
||||
#[test]
|
||||
fn simple() {
|
||||
let id = "8QRLaD".to_string();
|
||||
let numbers = vec![1, 2, 3];
|
||||
|
||||
let sqids = Sqids::new(None).unwrap();
|
||||
|
||||
let numbers = vec![1, 2, 3];
|
||||
let id = "8QRLaD";
|
||||
|
||||
assert_eq!(sqids.encode(&numbers).unwrap(), id);
|
||||
assert_eq!(sqids.decode(&id), numbers);
|
||||
assert_eq!(sqids.decode(id), numbers);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn different_inputs() {
|
||||
let sqids = Sqids::new(None).unwrap();
|
||||
|
||||
let numbers = vec![0, 0, 0, 1, 2, 3, 100, 1_000, 100_000, 1_000_000, sqids.max_value()];
|
||||
|
||||
assert_eq!(sqids.decode(&sqids.encode(&numbers).unwrap()), numbers);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn incremental_numbers() {
|
||||
let sqids = Sqids::new(None).unwrap();
|
||||
|
||||
let ids = vec![
|
||||
("bV", vec![0]),
|
||||
("U9", vec![1]),
|
||||
("g8", vec![2]),
|
||||
("Ez", vec![3]),
|
||||
("V8", vec![4]),
|
||||
("ul", vec![5]),
|
||||
("O3", vec![6]),
|
||||
("AF", vec![7]),
|
||||
("ph", vec![8]),
|
||||
("n8", vec![9]),
|
||||
];
|
||||
|
||||
for (id, numbers) in ids {
|
||||
assert_eq!(sqids.encode(&numbers).unwrap(), id);
|
||||
assert_eq!(sqids.decode(id), numbers);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn incremental_numbers_same_index_0() {
|
||||
let sqids = Sqids::new(None).unwrap();
|
||||
|
||||
let ids = vec![
|
||||
("SrIu", vec![0, 0]),
|
||||
("nZqE", vec![0, 1]),
|
||||
("tJyf", vec![0, 2]),
|
||||
("e86S", vec![0, 3]),
|
||||
("rtC7", vec![0, 4]),
|
||||
("sQ8R", vec![0, 5]),
|
||||
("uz2n", vec![0, 6]),
|
||||
("7Td9", vec![0, 7]),
|
||||
("3nWE", vec![0, 8]),
|
||||
("mIxM", vec![0, 9]),
|
||||
];
|
||||
|
||||
for (id, numbers) in ids {
|
||||
assert_eq!(sqids.encode(&numbers).unwrap(), id);
|
||||
assert_eq!(sqids.decode(id), numbers);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn incremental_numbers_same_index_1() {
|
||||
let sqids = Sqids::new(None).unwrap();
|
||||
|
||||
let ids = vec![
|
||||
("SrIu", vec![0, 0]),
|
||||
("nbqh", vec![1, 0]),
|
||||
("t4yj", vec![2, 0]),
|
||||
("eQ6L", vec![3, 0]),
|
||||
("r4Cc", vec![4, 0]),
|
||||
("sL82", vec![5, 0]),
|
||||
("uo2f", vec![6, 0]),
|
||||
("7Zdq", vec![7, 0]),
|
||||
("36Wf", vec![8, 0]),
|
||||
("m4xT", vec![9, 0]),
|
||||
];
|
||||
|
||||
for (id, numbers) in ids {
|
||||
assert_eq!(sqids.encode(&numbers).unwrap(), id);
|
||||
assert_eq!(sqids.decode(id), numbers);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn multi_input() {
|
||||
let sqids = Sqids::new(None).unwrap();
|
||||
|
||||
let numbers: Vec<u64> = (0..100).collect();
|
||||
let output = sqids.decode(&sqids.encode(&numbers).unwrap());
|
||||
|
||||
assert_eq!(numbers, output);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn encoding_no_numbers() {
|
||||
let sqids = Sqids::new(None).unwrap();
|
||||
assert_eq!(sqids.encode(&[]).unwrap(), "");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn decoding_empty_string() {
|
||||
let sqids = Sqids::new(None).unwrap();
|
||||
let numbers: Vec<u64> = vec![];
|
||||
assert_eq!(sqids.decode(""), numbers);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn decoding_invalid_character() {
|
||||
let sqids = Sqids::new(None).unwrap();
|
||||
let numbers: Vec<u64> = vec![];
|
||||
assert_eq!(sqids.decode("*"), numbers);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn encode_out_of_range_numbers() {
|
||||
let sqids = Sqids::new(None).unwrap();
|
||||
|
||||
assert!(sqids.encode(&[sqids.min_value() - 1]).is_err());
|
||||
assert!(sqids.encode(&[sqids.max_value() + 1]).is_err());
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user