1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90
//! A Rust-native implementation of Hashids.
//!
//! Hashids provides a few benefits. For a start, identifiers are more
//! difficult to confuse, provided that your selected alphabet does not
//! include easily-confused symbols such as o, 0, O, 1, l, and I.
//! Additionally, it becomes much more difficult for malicious or curious
//! users to increment an identifier to "see what happens" when they throw
//! it at your API. Lastly, Hashids values may combine several identifiers
//! into a single value.
//!
//! > **NOTE:** Hashids values are **not cryptographically secure.**
//! Regardless of the quality of your salt, this algorithm is fairly easy to
//! crack.
//!
//! Hashids should not be used for security purposes, but for your own
//! convenience.
//!
//! ## Creating and encoding
//!
//! [`Harsh`](./harsh/struct.Harsh.html) lacks a constructor (other than the
//! default constructor, which should not be used), and should be created
//! by the use of [`HarshBuilder`](./harsh/struct.HarshBuilder.html), which
//! allows for configuration with salts, alphabets, separators, and so forth.
//!
//! Initialization ensures that appropriate values have been provided for the
//! salt, alphabet, separators, and so forth, and in the event a struct cannot
//! be created in a usable state, an error will be returned.
//!
//! Encoding assumes zero or more input values and will return `None` in the
//! even that zero inputs have been provided.
//!
//! ```rust
//! # use harsh::Harsh;
//! # use std::error::Error;
//! # fn main() -> Result<(), Box<dyn Error>> {
//! let harsh = Harsh::builder().salt("salt goes here!").build()?;
//! let encoded = harsh.encode(&[1, 2, 3, 4, 5]);
//!
//! assert_eq!("xrUQTnhgu7", encoded);
//! # Ok(())
//! # }
//! ```
//!
//! ## Decoding
//!
//! Decoding likewise will return zero or more values in the form of a vector,
//! but may also return `None` in the event that the decoded value is not a
//! valid Hashid.
//!
//! ```rust
//! # use harsh::Harsh;
//! # use std::error::Error;
//! # fn main() -> Result<(), Box<dyn Error>> {
//! let harsh = Harsh::builder().salt("salt goes here!").build()?;
//! # let encoded = harsh.encode(&[1, 2, 3, 4, 5]);
//! let decoded = harsh.decode(&encoded)?;
//!
//! assert_eq!(&decoded, &[1, 2, 3, 4, 5]);
//! # Ok(())
//! # }
//! ```
mod builder;
mod harsh;
pub use crate::{
builder::{BuildError, HarshBuilder},
harsh::{Error, Harsh},
};
fn shuffle(values: &mut [u8], salt: &[u8]) {
if salt.is_empty() {
return;
}
let values_length = values.len();
let salt_length = salt.len();
let (mut v, mut p) = (0, 0);
for i in (1..values_length).map(|i| values_length - i) {
v %= salt_length;
let n = salt[v] as usize;
p += n;
let j = (n + v + p) % i;
values.swap(i, j);
v += 1;
}
}