light_id/
lib.rs

1//! # light_id
2//!
3//! `light_id` is a Rust crate for generating and manipulating light-weight IDs. It provides a flexible and customizable way to generate and switch between different bases for IDs.
4//!
5//! ## Features
6//!
7//! - Lightweight and customizable ID generation.
8//! - Switching IDs between different bases.
9//! - Skipping and iterating through IDs.
10//!
11//! ## Example
12//!
13//! ```rust
14//! use light_id::{LightId, IdSwitcher};
15//!
16//! let mut generator = LightId::new();
17//! println!("Current ID: {}", generator.next());
18//!
19//! let switcher = IdSwitcher::new("0123456789", "abcdef");
20//! let switched_id = switcher.switch("2");
21//! println!("Switched ID: {}", switched_id);
22//! ```
23//!
24//! ## Installation
25//!
26//! Add the following lines to your `Cargo.toml` file:
27//!
28//! ```toml
29//! [dependencies]
30//! light-id = "0.1.0"
31//! ```
32//!
33//! ## Usage
34//!
35//! ### LightId
36//!
37//! The `LightId` struct allows you to generate and manipulate IDs with various options.
38//!
39//! ```rust
40//! use light_id::LightId;
41//!
42//! let mut generator = LightId::new();
43//! generator.increment();
44//! println!("Current ID: {}", generator.current());
45//! ```
46//!
47//! ### IdSwitcher
48//!
49//! The `IdSwitcher` struct facilitates switching IDs between different bases.
50//!
51//! ```rust
52//! use light_id::IdSwitcher;
53//!
54//! let switcher = IdSwitcher::new("0123456789", "abcdef");
55//! let switched_id = switcher.switch("2");
56//! println!("Switched ID: {}", switched_id);
57//! ```
58//!
59//! ## API Documentation
60//!
61//! See the detailed documentation for each struct, including methods and usage examples.
62//!
63//! - [`LightId`](struct.LightId.html)
64//! - [`IdSwitcher`](struct.IdSwitcher.html)
65//!
66//! ## License
67//!
68//! This crate is licensed under the [MIT License](https://opensource.org/licenses/MIT).
69//!
70//! ## Changelog
71//!
72//! - **0.1.0** (2023-12-14): Initial release
73
74mod utils;
75
76pub const DEFAULT_CHARACTERS: &str =
77    "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
78
79pub struct LightId {
80    pub characters: Vec<char>,
81    pub min_length: usize,
82    status: usize,
83}
84
85impl PartialEq for LightId {
86    fn eq(&self, other: &Self) -> bool {
87        self.count() == other.count() && self.characters == other.characters
88    }
89}
90
91impl PartialOrd for LightId {
92    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
93        Some(self.count().cmp(&other.count()))
94    }
95}
96
97impl LightId {
98    /// Creates a new [`LightId`] with the default configuration.
99    /// ```
100    /// use light_id::LightId;
101    ///
102    /// let mut generator = LightId::new();
103    /// ```
104    pub fn new() -> Self {
105        LightId {
106            status: 0,
107            characters: DEFAULT_CHARACTERS.chars().collect(),
108            min_length: 0,
109        }
110    }
111
112    /// Creates a new [`LightId`] with a custom alphabet
113    /// ```
114    /// use light_id::LightId;
115    ///
116    /// let generator = LightId::from("abcdef");
117    /// ```
118    /// If the provided `characters` is equal to [`DEFAULT_CHARACTERS`], the expression can be replaced with
119    /// ```
120    /// use light_id::LightId;
121    ///
122    /// let generator = LightId::new();
123    /// ```
124    pub fn from<S: AsRef<str>>(characters: S) -> Self {
125        LightId {
126            status: 0,
127            characters: characters.as_ref().chars().collect(),
128            min_length: 0,
129        }
130    }
131
132    /// Skip the first `n` ids
133    /// ```
134    /// use light_id::LightId;
135    ///
136    /// let mut generator = LightId::new();
137    ///
138    /// generator.skip(2);
139    ///
140    /// assert_eq!("2", generator.current());
141    /// ```
142    pub fn skip(&mut self, n: usize) -> &mut Self {
143        self.status = n;
144
145        self
146    }
147
148    /// Skips the first ids until the provided id.
149    /// ```
150    /// use light_id::LightId;
151    ///
152    /// let mut generator = LightId::new();
153    ///
154    /// generator.last("c");
155    ///
156    /// assert_eq!("c", generator.current());
157    /// ```
158    pub fn last<S: AsRef<str>>(&mut self, id: S) -> &mut Self {
159        self.status = utils::parse_id(id.as_ref(), &self.characters);
160        self
161    }
162
163    /// Sets the min length of the ids
164    /// ```
165    /// use light_id::LightId;
166    ///
167    /// let mut generator = LightId::new();
168    ///
169    /// generator.min(6);
170    ///
171    /// assert_eq!("000000", generator.current());
172    /// ```
173    pub fn min(&mut self, n: usize) -> &mut Self {
174        self.min_length = n;
175
176        self
177    }
178
179    /// Sets the possible characters, in their order of importance (custom base)
180    /// ```
181    /// use light_id::LightId;
182    ///
183    /// let mut generator = LightId::new();
184    ///
185    /// generator.chars("abc");
186    ///
187    /// assert_eq!("a", generator.current());
188    /// ```
189    pub fn chars<S: AsRef<str>>(&mut self, characters: S) -> &mut Self {
190        self.characters = characters.as_ref().chars().collect();
191        self
192    }
193
194    /// Clone the current [`LighId`].
195    /// ```
196    /// use light_id::LightId;
197    ///
198    /// let mut generator = LightId::new();
199    ///
200    /// let mut generator2 = generator.clone();
201    /// ```
202    pub fn clone(&self) -> Self {
203        LightId {
204            status: self.status.clone(),
205            characters: self.characters.clone(),
206            min_length: self.min_length.clone(),
207        }
208    }
209
210    /// Returns the current number of ids
211    /// ```
212    /// use light_id::LightId;
213    ///
214    /// let mut generator = LightId::new();
215    ///
216    /// generator.increment();
217    ///
218    /// assert_eq!(1, generator.count());
219    /// ```
220    pub fn count(&self) -> usize {
221        return self.status;
222    }
223
224    /// Decrements the current id.
225    /// Internally uses an alias to [`LightId::decrement_by`]
226    /// ```
227    /// use light_id::LightId;
228    ///
229    /// let mut generator = LightId::new();
230    ///
231    /// generator.increment();
232    /// generator.decrement();
233    ///
234    /// assert_eq!("0", generator.current());
235    /// ```
236    pub fn decrement(&mut self) -> &mut Self {
237        self.decrement_by(1)
238    }
239
240    /// Decrements the current id with a given factor
241    /// ```
242    /// use light_id::LightId;
243    ///
244    /// let mut generator = LightId::new();
245    ///
246    /// generator.increment_by(10);
247    /// generator.decrement_by(10);
248    ///
249    /// assert_eq!("0", generator.current());
250    /// ```
251    pub fn decrement_by(&mut self, count: usize) -> &mut Self {
252        if count > self.status {
253            self.status = 0;
254        } else {
255            self.status -= count;
256        }
257        self
258    }
259
260    /// Increments the current id by one.
261    /// Internally uses an alias to [`LightId::increment_by`]
262    /// ```
263    /// use light_id::LightId;
264    ///
265    /// let mut generator = LightId::new();
266    ///
267    /// generator.increment();
268    ///
269    /// assert_eq!("1", generator.current());
270    /// ```
271    pub fn increment(&mut self) -> &mut Self {
272        self.increment_by(1)
273    }
274
275    /// Increments the current id with a given factor
276    /// ```
277    /// use light_id::LightId;
278    ///
279    /// let mut generator = LightId::new();
280    ///
281    /// generator.increment_by(10);
282    ///
283    /// assert_eq!("a", generator.current());
284    /// ```
285    pub fn increment_by(&mut self, count: usize) -> &mut Self {
286        self.status += count;
287
288        self
289    }
290
291    /// Increments the id by one and returns it.
292    /// ```
293    /// use light_id::LightId;
294    ///
295    /// let mut generator = LightId::new();
296    ///
297    /// assert_eq!("0", generator.next());
298    /// assert_eq!("1", generator.next());
299    /// assert_eq!("2", generator.next());
300    /// ```
301    /// Internally uses an alias to [`LightId::current`] and [`LightId::increment`]
302    /// ```
303    /// use light_id::LightId;
304    ///
305    /// let mut generator = LightId::new();
306    ///
307    /// let value = generator.current();
308    /// generator.increment();
309    ///
310    /// assert_eq!("0", value);
311    /// ```
312    pub fn next(&mut self) -> String {
313        self.status += 1;
314        utils::format_id(&(&self.status - 1), &self.min_length, &self.characters)
315    }
316
317    /// Returns the current id.
318    /// ```
319    /// use light_id::LightId;
320    ///
321    /// let mut generator = LightId::new();
322    ///
323    /// assert_eq!("0", generator.current());
324    /// ```
325    pub fn current(&self) -> String {
326        utils::format_id(&self.status, &self.min_length, &self.characters)
327    }
328
329    /// Returns the length of the current id.
330    /// ```
331    /// use light_id::LightId;
332    ///
333    /// let mut generator = LightId::new();
334    ///
335    /// assert_eq!(1, generator.len());
336    ///
337    /// generator.increment_by(100);
338    ///
339    /// assert_eq!(2, generator.len());
340    /// ```
341    pub fn len(&self) -> usize {
342        if self.status == 0 {
343            return std::cmp::max(self.min_length, 1);
344        }
345        return std::cmp::max(
346            self.min_length,
347            self.status.ilog(self.characters.len()) as usize + 1,
348        );
349    }
350
351    /// Returns the nth id.
352    /// ```
353    /// use light_id::LightId;
354    /// 
355    /// let generator = LightId::new();
356    /// 
357    /// assert_eq!("2", generator.nth(2));
358    /// ```
359    pub fn nth(&self, n: usize) -> String {
360        utils::format_id(&n, &self.min_length, &self.characters)
361    }
362
363    /// Returns the index of the provided id
364    /// ```
365    /// use light_id::LightId;
366    /// 
367    /// let generator = LightId::new();
368    /// 
369    /// assert_eq!(2, generator.index("2"));
370    /// ```
371    pub fn index<S: AsRef<str>>(&self, id: S) -> usize {
372        utils::parse_id(id.as_ref(), &self.characters)
373    }
374}
375
376pub struct IdSwitcher {
377    source: Vec<char>,
378    source_min: usize,
379    target: Vec<char>,
380    target_min: usize,
381}
382
383impl IdSwitcher {
384
385    /// Create a new [`IdSwitcher`].
386    /// It can be used to switch the ids from a source base to a target base.
387    /// ```
388    /// use light_id::IdSwitcher;
389    /// 
390    /// let switcher = IdSwitcher::new("0123456789", "abcdefghij");
391    /// ```
392    pub fn new<S: AsRef<str>>(source: S, target: S) -> Self {
393        IdSwitcher {
394            source: source.as_ref().chars().collect(),
395            source_min: 0,
396            target: target.as_ref().chars().collect(),
397            target_min: 0
398        }
399    }
400
401    /// Returns a copy of the [`IdSwitcher`].
402    /// ```
403    /// use light_id::IdSwitcher;
404    /// 
405    /// let switcher = IdSwitcher::new("0123456789", "abcdefghij");
406    /// let switcher_2 = switcher.clone();
407    /// ```
408    pub fn clone (&self) -> Self {
409        IdSwitcher {
410            source: self.source.clone(),
411            source_min: self.source_min.clone(),
412            target: self.target.clone(),
413            target_min: self.target_min.clone(),
414        }
415    }
416
417    /// Sets the min length of the converted ids.
418    /// ```
419    /// use light_id::IdSwitcher;
420    /// 
421    /// let mut switcher = IdSwitcher::new("0123456789", "abcdefghij");
422    /// 
423    /// switcher.min_target(10);
424    /// 
425    /// assert_eq!("aaaaaaaaaa", switcher.switch("0"));
426    /// ```
427    pub fn min_target(&mut self, n: usize) -> &mut Self {
428        self.target_min = n;
429
430        self
431    }
432
433    /// Sets the min length of the source ids.
434    /// ```
435    /// use light_id::IdSwitcher;
436    /// 
437    /// let mut switcher = IdSwitcher::new("0123456789", "abcdefghij");
438    /// 
439    /// switcher.min_source(10);
440    /// 
441    /// assert_eq!("0000000000", switcher.switch_reverse("a"));
442    /// ```
443    pub fn min_source(&mut self, n: usize) -> &mut Self {
444        self.source_min = n;
445
446        self
447    }
448
449    /// Switches an id count from the source base to the target base.
450    /// ```
451    /// use light_id::IdSwitcher;
452    /// 
453    /// let switcher = IdSwitcher::new("0123456789", "abcdefghij");
454    /// 
455    /// assert_eq!("a", switcher.switch_count(0));
456    /// ```
457    pub fn switch_count(&self, id: usize) -> String {
458        utils::format_id(&id, &self.target_min, &self.target)
459    }
460
461    /// Switches an id from the source base to the target base.
462    /// ```
463    /// use light_id::IdSwitcher;
464    /// 
465    /// let switcher = IdSwitcher::new("0123456789", "abcdefghij");
466    /// 
467    /// assert_eq!("a", switcher.switch("0"));
468    /// ```
469    pub fn switch<S: AsRef<str>>(&self, id: S) -> String {
470        self.switch_count(utils::parse_id(id.as_ref(), &self.source))
471    }
472
473    /// Switches an id count from the target base to the source base.
474    /// ```
475    /// use light_id::IdSwitcher;
476    /// 
477    /// let switcher = IdSwitcher::new("0123456789", "abcdefghij");
478    /// 
479    /// assert_eq!("0", switcher.switch_count_reverse(0));
480    /// ```
481    pub fn switch_count_reverse(&self, id: usize) -> String {
482        utils::format_id(&id, &self.source_min, &self.source)
483    }
484
485    /// Switches an id from the target base to the source base.
486    /// ```
487    /// use light_id::IdSwitcher;
488    /// 
489    /// let switcher = IdSwitcher::new("0123456789", "abcdefghij");
490    /// 
491    /// assert_eq!("0", switcher.switch_reverse("a"));
492    /// ```
493    pub fn switch_reverse<S: AsRef<str>>(&self, id: S) -> String {
494        self.switch_count_reverse(utils::parse_id(id.as_ref(), &self.target))
495    }
496}