short_id/lib.rs
1//! A tiny crate for generating short, URL-safe, unique identifiers.
2//!
3//! Unlike full UUIDs (which are 36 characters and include hyphens), `short-id` gives you
4//! compact 14-character strings that are easy to copy, paste, and use in URLs.
5//!
6//! # Goals
7//!
8//! 1. **Make it very easy to generate short random IDs** for things like request IDs,
9//! user-facing tokens, test data, and log correlation.
10//!
11//! 2. **Provide an optional "ordered" variant** where IDs include a timestamp prefix,
12//! so when you sort them as strings they roughly follow creation time.
13//!
14//! This crate is intentionally minimal - no configuration, no custom alphabets, no complex API.
15//!
16//! # Quick Start
17//!
18//! ```
19//! use short_id::short_id;
20//!
21//! // Generate a random ID
22//! let id = short_id();
23//! println!("Request ID: {}", id);
24//! // Example output: "X7K9mP2nQwE-Tg"
25//! ```
26//!
27//! For time-ordered IDs:
28//!
29//! ```
30//! use short_id::short_id_ordered;
31//!
32//! let id1 = short_id_ordered();
33//! std::thread::sleep(std::time::Duration::from_millis(100));
34//! let id2 = short_id_ordered();
35//!
36//! // IDs from different times are different
37//! assert_ne!(id1, id2);
38//! ```
39//!
40//! # Use Cases
41//!
42//! - Request IDs for logging and tracing
43//! - User-facing tokens and session IDs
44//! - Test data generation
45//! - Short URLs and resource identifiers
46//! - Any place you want something shorter and simpler than UUIDs
47//!
48//! # Characteristics
49//!
50//! - **Length**: Always exactly 14 characters (default)
51//! - **URL-safe**: Only `A-Z`, `a-z`, `0-9`, `-`, `_` (no special characters)
52//! - **Cryptographically secure**: Uses `OsRng` for random bytes
53//! - **No configuration needed**: Just call the function
54//!
55//! # Advanced: Custom Length IDs
56//!
57//! For advanced use cases, you can control the ID length by specifying the number of random bytes:
58//!
59//! ```
60//! use short_id::{short_id_with_bytes, short_id_ordered_with_bytes};
61//!
62//! // Generate a shorter 8-character ID (6 bytes)
63//! let short = short_id_with_bytes(6);
64//! assert_eq!(short.len(), 8);
65//!
66//! // Generate a longer 22-character ID (16 bytes)
67//! let long = short_id_with_bytes(16);
68//! assert_eq!(long.len(), 22);
69//!
70//! // Time-ordered IDs also support custom lengths
71//! let ordered = short_id_ordered_with_bytes(12);
72//! ```
73//!
74//! **When to use custom lengths:**
75//!
76//! - **Fewer bytes (e.g., 4-6)**: Use for low-volume applications where you need very short IDs
77//! and collision risk is acceptable. Keep in mind that 6 bytes provides only ~48 bits of entropy.
78//!
79//! - **Default (10 bytes)**: Recommended for most applications. Provides ~80 bits of entropy
80//! with 14-character IDs. The [`short_id()`] and [`short_id_ordered()`] functions use this.
81//!
82//! - **More bytes (e.g., 16-32)**: Use for high-volume applications or when you need extra
83//! safety margin. 16 bytes provides ~128 bits of entropy.
84//!
85//! **Important:** Using fewer bytes significantly increases collision probability. For most users,
86//! the default [`short_id()`] and [`short_id_ordered()`] functions are recommended.
87//!
88//! # Features
89//!
90//! - **`std`** (enabled by default): Enables [`short_id_ordered()`] and [`short_id_ordered_with_bytes()`]
91//! which need `std::time::SystemTime`
92//!
93//! For `no_std` environments with `alloc`:
94//!
95//! ```toml
96//! [dependencies]
97//! short-id = { version = "0.4", default-features = false }
98//! ```
99//!
100//! In `no_std` mode, only [`short_id()`] and [`short_id_with_bytes()`] are available.
101
102#![cfg_attr(not(feature = "std"), no_std)]
103
104#[cfg(not(feature = "std"))]
105extern crate alloc;
106
107#[cfg(not(feature = "std"))]
108use alloc::string::String;
109
110#[cfg(not(feature = "std"))]
111use alloc::vec;
112
113#[cfg(feature = "std")]
114use std::vec;
115
116use base64::{engine::general_purpose::URL_SAFE_NO_PAD, Engine as _};
117use rand::{rngs::OsRng, RngCore};
118
119/// Maximum number of random bytes allowed for custom-length ID generation.
120///
121/// This limit prevents excessive memory allocation and ensures reasonable ID sizes.
122const MAX_BYTES: usize = 32;
123
124/// Convenience macro for generating a random short ID.
125///
126/// This macro simply calls [`short_id()`] and is provided for ergonomics.
127///
128/// # Examples
129///
130/// ```
131/// use short_id::id;
132///
133/// let request_id = id!();
134/// assert_eq!(request_id.len(), 14);
135/// ```
136#[macro_export]
137macro_rules! id {
138 () => {
139 $crate::short_id()
140 };
141}
142
143/// Convenience macro for generating a time-ordered short ID.
144///
145/// This macro simply calls [`short_id_ordered()`] and is provided for ergonomics.
146/// Requires the `std` feature (enabled by default).
147///
148/// # Examples
149///
150/// ```
151/// use short_id::ordered_id;
152///
153/// let log_id = ordered_id!();
154/// assert_eq!(log_id.len(), 14);
155/// ```
156#[cfg(feature = "std")]
157#[macro_export]
158macro_rules! ordered_id {
159 () => {
160 $crate::short_id_ordered()
161 };
162}
163
164/// Internal helper: generates a random ID with the specified number of bytes.
165///
166/// # Panics
167///
168/// Panics if `num_bytes` is 0 or exceeds `MAX_BYTES`.
169fn generate_random_id(num_bytes: usize) -> String {
170 assert!(num_bytes > 0, "num_bytes must be greater than 0");
171 assert!(
172 num_bytes <= MAX_BYTES,
173 "num_bytes must not exceed {} (got {})",
174 MAX_BYTES,
175 num_bytes
176 );
177
178 let mut bytes = vec![0u8; num_bytes];
179 OsRng.fill_bytes(&mut bytes);
180 URL_SAFE_NO_PAD.encode(&bytes)
181}
182
183/// Generates a random, URL-safe short ID.
184///
185/// Creates a 14-character ID from 10 cryptographically secure random bytes,
186/// encoded with base64url (no padding).
187///
188/// # Examples
189///
190/// Basic usage:
191///
192/// ```
193/// use short_id::short_id;
194///
195/// let id = short_id();
196/// assert_eq!(id.len(), 14);
197/// ```
198///
199/// Use for request IDs:
200///
201/// ```
202/// use short_id::short_id;
203///
204/// fn handle_request() -> String {
205/// let request_id = short_id();
206/// println!("Processing request {}", request_id);
207/// request_id
208/// }
209///
210/// let id = handle_request();
211/// assert_eq!(id.len(), 14);
212/// ```
213///
214/// Generate multiple unique IDs:
215///
216/// ```
217/// use short_id::short_id;
218///
219/// let ids: Vec<String> = (0..10).map(|_| short_id()).collect();
220///
221/// // All IDs are unique
222/// for i in 0..ids.len() {
223/// for j in i+1..ids.len() {
224/// assert_ne!(ids[i], ids[j]);
225/// }
226/// }
227/// ```
228///
229/// IDs are URL-safe:
230///
231/// ```
232/// use short_id::short_id;
233///
234/// let id = short_id();
235/// let url = format!("https://example.com/resource/{}", id);
236/// // No encoding needed - safe to use directly
237/// ```
238pub fn short_id() -> String {
239 generate_random_id(10)
240}
241
242/// Internal helper: generates a time-ordered ID with the specified number of bytes.
243///
244/// Uses 8 bytes for timestamp and fills the remaining bytes with random data.
245///
246/// # Panics
247///
248/// Panics if `num_bytes` is less than 8, is 0, or exceeds `MAX_BYTES`.
249#[cfg(feature = "std")]
250fn generate_ordered_id(num_bytes: usize) -> String {
251 assert!(
252 num_bytes >= 8,
253 "num_bytes must be at least 8 for ordered IDs (got {})",
254 num_bytes
255 );
256 assert!(
257 num_bytes <= MAX_BYTES,
258 "num_bytes must not exceed {} (got {})",
259 MAX_BYTES,
260 num_bytes
261 );
262
263 let timestamp_us = std::time::SystemTime::now()
264 .duration_since(std::time::UNIX_EPOCH)
265 .expect("system time before Unix epoch")
266 .as_micros() as u64;
267
268 let mut bytes = vec![0u8; num_bytes];
269 bytes[0..8].copy_from_slice(×tamp_us.to_be_bytes());
270 OsRng.fill_bytes(&mut bytes[8..]);
271
272 URL_SAFE_NO_PAD.encode(&bytes)
273}
274
275/// Generates a time-ordered, URL-safe short ID.
276///
277/// Creates a 14-character ID with microsecond-precision timestamp for excellent time
278/// resolution when generating IDs in rapid succession. The ID consists of:
279/// - First 8 bytes: Unix timestamp (microseconds since epoch) as big-endian u64
280/// - Next 2 bytes: Cryptographically secure random bytes
281///
282/// With microsecond precision, IDs created within the same microsecond will differ
283/// by their random component (65,536 possible values per microsecond).
284///
285/// **This function requires the `std` feature** (enabled by default).
286///
287/// # Examples
288///
289/// Basic usage:
290///
291/// ```
292/// use short_id::short_id_ordered;
293///
294/// let id = short_id_ordered();
295/// assert_eq!(id.len(), 14);
296/// ```
297///
298/// IDs from different times differ:
299///
300/// ```
301/// use short_id::short_id_ordered;
302///
303/// let id1 = short_id_ordered();
304/// std::thread::sleep(std::time::Duration::from_millis(100));
305/// let id2 = short_id_ordered();
306///
307/// // IDs generated at different times are different
308/// assert_ne!(id1, id2);
309/// ```
310///
311/// Even within the same second, IDs are unique:
312///
313/// ```
314/// use short_id::short_id_ordered;
315///
316/// let ids: Vec<String> = (0..10).map(|_| short_id_ordered()).collect();
317///
318/// // All unique due to random component
319/// for i in 0..ids.len() {
320/// for j in i+1..ids.len() {
321/// assert_ne!(ids[i], ids[j]);
322/// }
323/// }
324/// ```
325///
326/// Use for log entries:
327///
328/// ```
329/// use short_id::short_id_ordered;
330///
331/// struct LogEntry {
332/// id: String,
333/// message: String,
334/// }
335///
336/// impl LogEntry {
337/// fn new(message: String) -> Self {
338/// LogEntry {
339/// id: short_id_ordered(),
340/// message,
341/// }
342/// }
343/// }
344///
345/// let log = LogEntry::new("Started processing".to_string());
346/// assert_eq!(log.id.len(), 14);
347/// ```
348#[cfg(feature = "std")]
349pub fn short_id_ordered() -> String {
350 generate_ordered_id(10)
351}
352
353/// **Advanced:** Generates a random, URL-safe short ID with a custom number of bytes.
354///
355/// This is an advanced API that allows you to control the ID length by specifying
356/// the number of random bytes to use. The ID is encoded using URL-safe base64 without
357/// padding, so the resulting string length will be approximately `(num_bytes * 4) / 3`.
358///
359/// **For most users, [`short_id()`] is the recommended API.**
360///
361/// # Parameters
362///
363/// - `num_bytes`: Number of random bytes to generate (1 to 32 inclusive)
364///
365/// # Panics
366///
367/// Panics if `num_bytes` is 0 or exceeds 32.
368///
369/// # Security Note
370///
371/// **Using fewer bytes reduces entropy and increases collision probability.**
372/// - 10 bytes (default): ~80 bits of entropy, collision probability ~1 in 10^24
373/// - 6 bytes: ~48 bits of entropy, collision probability ~1 in 10^14
374/// - 4 bytes: ~32 bits of entropy, collision probability ~1 in 4 billion
375///
376/// Choose an appropriate size based on your uniqueness requirements and expected scale.
377///
378/// # Examples
379///
380/// Generate a standard 14-character ID (equivalent to `short_id()`):
381///
382/// ```
383/// use short_id::short_id_with_bytes;
384///
385/// let id = short_id_with_bytes(10);
386/// assert_eq!(id.len(), 14);
387/// ```
388///
389/// Generate a shorter 8-character ID with less entropy:
390///
391/// ```
392/// use short_id::short_id_with_bytes;
393///
394/// let short_id = short_id_with_bytes(6);
395/// assert_eq!(short_id.len(), 8);
396/// // Suitable for small-scale applications with fewer expected IDs
397/// ```
398///
399/// Generate a longer ID with more entropy:
400///
401/// ```
402/// use short_id::short_id_with_bytes;
403///
404/// let long_id = short_id_with_bytes(16);
405/// assert_eq!(long_id.len(), 22);
406/// // Extra safety margin for high-volume applications
407/// ```
408///
409/// All IDs are URL-safe regardless of size:
410///
411/// ```
412/// use short_id::short_id_with_bytes;
413///
414/// let id = short_id_with_bytes(6);
415/// let url = format!("https://example.com/resource/{}", id);
416/// // No encoding needed - safe to use directly
417/// ```
418pub fn short_id_with_bytes(num_bytes: usize) -> String {
419 generate_random_id(num_bytes)
420}
421
422/// **Advanced:** Generates a time-ordered, URL-safe short ID with a custom number of bytes.
423///
424/// This is an advanced API that allows you to control the ID length by specifying
425/// the number of bytes to use. The first 8 bytes always contain a microsecond-precision
426/// timestamp, and the remaining bytes are filled with cryptographically secure random data.
427///
428/// **For most users, [`short_id_ordered()`] is the recommended API.**
429///
430/// **This function requires the `std` feature** (enabled by default).
431///
432/// # Parameters
433///
434/// - `num_bytes`: Total number of bytes for the ID (8 to 32 inclusive, must be at least 8 for the timestamp)
435///
436/// # Panics
437///
438/// Panics if `num_bytes` is less than 8 or exceeds 32.
439///
440/// # Security Note
441///
442/// **Using fewer random bytes (beyond the 8-byte timestamp) reduces uniqueness within the same microsecond.**
443/// - 10 bytes (default): 8 bytes timestamp + 2 bytes random (~16 bits randomness per microsecond)
444/// - 8 bytes: timestamp only, no randomness (IDs in the same microsecond will collide!)
445/// - 16 bytes: 8 bytes timestamp + 8 bytes random (~64 bits randomness per microsecond)
446///
447/// # Examples
448///
449/// Generate a standard time-ordered ID (equivalent to `short_id_ordered()`):
450///
451/// ```
452/// use short_id::short_id_ordered_with_bytes;
453///
454/// let id = short_id_ordered_with_bytes(10);
455/// assert_eq!(id.len(), 14);
456/// ```
457///
458/// IDs from different times contain different timestamps:
459///
460/// ```
461/// use short_id::short_id_ordered_with_bytes;
462///
463/// let id1 = short_id_ordered_with_bytes(10);
464/// std::thread::sleep(std::time::Duration::from_millis(10));
465/// let id2 = short_id_ordered_with_bytes(10);
466///
467/// // IDs from different times are different
468/// assert_ne!(id1, id2);
469/// ```
470///
471/// Shorter time-ordered IDs with minimal randomness:
472///
473/// ```
474/// use short_id::short_id_ordered_with_bytes;
475///
476/// let id = short_id_ordered_with_bytes(8);
477/// assert_eq!(id.len(), 11);
478/// // Warning: No random component! Only suitable if you never generate
479/// // multiple IDs within the same microsecond.
480/// ```
481///
482/// Longer time-ordered IDs with extra randomness:
483///
484/// ```
485/// use short_id::short_id_ordered_with_bytes;
486///
487/// let id = short_id_ordered_with_bytes(16);
488/// assert_eq!(id.len(), 22);
489/// // 8 bytes random component provides excellent uniqueness
490/// // even when generating millions of IDs per second
491/// ```
492#[cfg(feature = "std")]
493pub fn short_id_ordered_with_bytes(num_bytes: usize) -> String {
494 generate_ordered_id(num_bytes)
495}
496
497#[cfg(test)]
498mod tests {
499 use super::*;
500
501 #[test]
502 fn test_short_id_length() {
503 let id = short_id();
504 assert_eq!(id.len(), 14);
505 }
506
507 #[test]
508 fn test_short_id_unique() {
509 let id1 = short_id();
510 let id2 = short_id();
511 assert_ne!(id1, id2);
512 }
513
514 #[test]
515 fn test_short_id_url_safe() {
516 for _ in 0..100 {
517 let id = short_id();
518 assert!(!id.contains('+'));
519 assert!(!id.contains('/'));
520 assert!(!id.contains('='));
521 }
522 }
523
524 #[test]
525 fn test_many_unique_ids() {
526 // Generate many IDs and ensure all are unique
527 #[cfg(feature = "std")]
528 {
529 let ids: Vec<String> = (0..1000).map(|_| short_id()).collect();
530 let unique_count = ids.iter().collect::<std::collections::HashSet<_>>().len();
531 assert_eq!(unique_count, 1000);
532 }
533
534 #[cfg(not(feature = "std"))]
535 {
536 // In no_std, just verify a few IDs are unique
537 let id1 = short_id();
538 let id2 = short_id();
539 let id3 = short_id();
540 assert_ne!(id1, id2);
541 assert_ne!(id2, id3);
542 assert_ne!(id1, id3);
543 }
544 }
545
546 #[cfg(feature = "std")]
547 #[test]
548 fn test_short_id_ordered_length() {
549 let id = short_id_ordered();
550 assert_eq!(id.len(), 14);
551 }
552
553 #[cfg(feature = "std")]
554 #[test]
555 fn test_short_id_ordered_unique() {
556 let id1 = short_id_ordered();
557 let id2 = short_id_ordered();
558 assert_ne!(id1, id2);
559 }
560
561 #[cfg(feature = "std")]
562 #[test]
563 fn test_short_id_ordered_includes_timestamp() {
564 // Generate IDs and verify they contain timestamp information
565 // by checking they change over time
566 let id1 = short_id_ordered();
567 std::thread::sleep(std::time::Duration::from_secs(1));
568 let id2 = short_id_ordered();
569
570 // IDs from different times should differ
571 assert_ne!(id1, id2);
572 }
573
574 #[cfg(feature = "std")]
575 #[test]
576 fn test_short_id_ordered_url_safe() {
577 for _ in 0..100 {
578 let id = short_id_ordered();
579 assert!(!id.contains('+'));
580 assert!(!id.contains('/'));
581 assert!(!id.contains('='));
582 }
583 }
584
585 // Tests for short_id_with_bytes
586
587 #[test]
588 fn test_short_id_with_bytes_standard() {
589 let id = short_id_with_bytes(10);
590 assert_eq!(id.len(), 14);
591 }
592
593 #[test]
594 fn test_short_id_with_bytes_shorter() {
595 let id = short_id_with_bytes(6);
596 assert_eq!(id.len(), 8);
597 }
598
599 #[test]
600 fn test_short_id_with_bytes_longer() {
601 let id = short_id_with_bytes(16);
602 assert_eq!(id.len(), 22);
603 }
604
605 #[test]
606 fn test_short_id_with_bytes_url_safe() {
607 for num_bytes in [6, 10, 16, 32] {
608 let id = short_id_with_bytes(num_bytes);
609 assert!(!id.contains('+'));
610 assert!(!id.contains('/'));
611 assert!(!id.contains('='));
612 }
613 }
614
615 #[test]
616 fn test_short_id_with_bytes_unique() {
617 // Generate many IDs with different byte counts
618 for num_bytes in [6, 10, 16] {
619 let id1 = short_id_with_bytes(num_bytes);
620 let id2 = short_id_with_bytes(num_bytes);
621 assert_ne!(id1, id2);
622 }
623 }
624
625 #[test]
626 #[should_panic(expected = "num_bytes must be greater than 0")]
627 fn test_short_id_with_bytes_zero_panics() {
628 short_id_with_bytes(0);
629 }
630
631 #[test]
632 #[should_panic(expected = "num_bytes must not exceed 32")]
633 fn test_short_id_with_bytes_too_large_panics() {
634 short_id_with_bytes(33);
635 }
636
637 // Tests for short_id_ordered_with_bytes
638
639 #[cfg(feature = "std")]
640 #[test]
641 fn test_short_id_ordered_with_bytes_standard() {
642 let id = short_id_ordered_with_bytes(10);
643 assert_eq!(id.len(), 14);
644 }
645
646 #[cfg(feature = "std")]
647 #[test]
648 fn test_short_id_ordered_with_bytes_minimal() {
649 let id = short_id_ordered_with_bytes(8);
650 assert_eq!(id.len(), 11);
651 }
652
653 #[cfg(feature = "std")]
654 #[test]
655 fn test_short_id_ordered_with_bytes_longer() {
656 let id = short_id_ordered_with_bytes(16);
657 assert_eq!(id.len(), 22);
658 }
659
660 #[cfg(feature = "std")]
661 #[test]
662 fn test_short_id_ordered_with_bytes_url_safe() {
663 for num_bytes in [8, 10, 16, 32] {
664 let id = short_id_ordered_with_bytes(num_bytes);
665 assert!(!id.contains('+'));
666 assert!(!id.contains('/'));
667 assert!(!id.contains('='));
668 }
669 }
670
671 #[cfg(feature = "std")]
672 #[test]
673 fn test_short_id_ordered_with_bytes_includes_timestamp() {
674 // Generate IDs with different byte sizes and verify they contain timestamp information
675 // by checking that IDs generated at different times are different
676 for num_bytes in [8, 10, 16] {
677 let id1 = short_id_ordered_with_bytes(num_bytes);
678 std::thread::sleep(std::time::Duration::from_secs(1));
679 let id2 = short_id_ordered_with_bytes(num_bytes);
680
681 // IDs from different times should differ
682 assert_ne!(id1, id2, "IDs from different times should be different");
683 }
684 }
685
686 #[cfg(feature = "std")]
687 #[test]
688 fn test_short_id_ordered_with_bytes_unique() {
689 // Even with same timestamp, random component makes them unique
690 for num_bytes in [10, 16] {
691 let id1 = short_id_ordered_with_bytes(num_bytes);
692 let id2 = short_id_ordered_with_bytes(num_bytes);
693 assert_ne!(id1, id2);
694 }
695 }
696
697 #[cfg(feature = "std")]
698 #[test]
699 #[should_panic(expected = "num_bytes must be at least 8 for ordered IDs")]
700 fn test_short_id_ordered_with_bytes_too_small_panics() {
701 short_id_ordered_with_bytes(7);
702 }
703
704 #[cfg(feature = "std")]
705 #[test]
706 #[should_panic(expected = "num_bytes must not exceed 32")]
707 fn test_short_id_ordered_with_bytes_too_large_panics() {
708 short_id_ordered_with_bytes(33);
709 }
710}
711
712/// A newtype wrapper around a short ID string.
713///
714/// Provides a typed interface for working with short IDs, with methods for
715/// generation and conversion. The inner string is always a valid 14-character
716/// URL-safe identifier.
717///
718/// # Examples
719///
720/// ```
721/// use short_id::ShortId;
722///
723/// // Generate a random ID
724/// let id = ShortId::random();
725/// assert_eq!(id.as_str().len(), 14);
726///
727/// // Convert to string
728/// let s: String = id.into_string();
729/// ```
730#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
731pub struct ShortId(String);
732
733impl ShortId {
734 /// Creates a new random short ID.
735 ///
736 /// This is equivalent to calling [`short_id()`] but returns a typed [`ShortId`].
737 ///
738 /// # Examples
739 ///
740 /// ```
741 /// use short_id::ShortId;
742 ///
743 /// let id = ShortId::random();
744 /// assert_eq!(id.as_str().len(), 14);
745 /// ```
746 pub fn random() -> Self {
747 ShortId(short_id())
748 }
749
750 /// Creates a new time-ordered short ID.
751 ///
752 /// This is equivalent to calling [`short_id_ordered()`] but returns a typed [`ShortId`].
753 /// Requires the `std` feature (enabled by default).
754 ///
755 /// # Examples
756 ///
757 /// ```
758 /// use short_id::ShortId;
759 ///
760 /// let id = ShortId::ordered();
761 /// assert_eq!(id.as_str().len(), 14);
762 /// ```
763 #[cfg(feature = "std")]
764 pub fn ordered() -> Self {
765 ShortId(short_id_ordered())
766 }
767
768 /// Returns the ID as a string slice.
769 ///
770 /// # Examples
771 ///
772 /// ```
773 /// use short_id::ShortId;
774 ///
775 /// let id = ShortId::random();
776 /// let s: &str = id.as_str();
777 /// assert_eq!(s.len(), 14);
778 /// ```
779 pub fn as_str(&self) -> &str {
780 &self.0
781 }
782
783 /// Consumes the `ShortId` and returns the inner `String`.
784 ///
785 /// # Examples
786 ///
787 /// ```
788 /// use short_id::ShortId;
789 ///
790 /// let id = ShortId::random();
791 /// let s: String = id.into_string();
792 /// assert_eq!(s.len(), 14);
793 /// ```
794 pub fn into_string(self) -> String {
795 self.0
796 }
797}
798
799impl core::fmt::Display for ShortId {
800 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
801 write!(f, "{}", self.0)
802 }
803}
804
805impl AsRef<str> for ShortId {
806 fn as_ref(&self) -> &str {
807 &self.0
808 }
809}
810
811impl From<String> for ShortId {
812 fn from(s: String) -> Self {
813 ShortId(s)
814 }
815}
816
817impl From<ShortId> for String {
818 fn from(id: ShortId) -> Self {
819 id.0
820 }
821}