lexis/lib.rs
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
//
// lexis: Generates human-readable sequences from numeric values using a predefined word list
// src/lib.rs: Common utility functions
//
// Copyright (c) 2024 Ali Polatel <alip@chesswob.org>
//
// SPDX-License-Identifier: GPL-3.0-or-later
/// Predefined word lists
pub mod list;
use std::{
collections::hash_map::DefaultHasher,
hash::{Hash, Hasher},
};
use crate::list::{ADJECTIVES, NAMES, WORDS};
/// Provides functionality to convert numeric values to reproducible, human-readable names.
pub trait ToName {
fn to_name(&self) -> String;
}
/// Trait to be implemented by unsigned integers to convert to human-readable string.
pub trait ToWordSequence {
fn to_word_sequence(&self) -> String;
}
/// Helper function to convert an unsigned number to a name sequence using predefined adjectives and names.
fn number_to_name<U: Into<u64>>(number: U) -> String {
// Convert the input number into a u64 and hash it for a uniform distribution.
let num = hash_number(number.into());
// Calculate indexes for the adjective and name using the hash value.
// The modulo operation ensures that the index is within the bounds of the lists.
let adjective_index = (num % (ADJECTIVES.len() as u64)) as usize;
let name_index = (num / (ADJECTIVES.len() as u64) % (NAMES.len() as u64)) as usize;
// Construct the human-readable name by concatenating an adjective and a name from the lists.
format!("{}_{}", ADJECTIVES[adjective_index], NAMES[name_index])
}
/// Helper function to convert an unsigned number to a word sequence.
fn number_to_words<U: Into<u64>>(number: U) -> String {
// Convert the input number into a u64 and hash it for a uniform distribution.
let mut num = hash_number(number.into());
let mut words = Vec::new();
while num > 0 {
let index = (num % 2048) as usize;
words.push(WORDS[index]);
num /= 2048;
}
words.reverse();
words.join(" ")
}
/// Uses the DefaultHasher to hash an u64 number.
fn hash_number(number: u64) -> u64 {
let mut hasher = DefaultHasher::new();
number.hash(&mut hasher);
hasher.finish()
}
/// Macro to implement `ToName` for common unsigned integer types.
macro_rules! impl_to_name {
($($t:ty),*) => {
$(impl ToName for $t {
fn to_name(&self) -> String {
number_to_name(*self)
}
})*
};
}
/// Macro to implement `ToWordSequence` for common unsigned integer types.
macro_rules! impl_to_word_sequence {
($($t:ty),*) => {
$(impl ToWordSequence for $t {
fn to_word_sequence(&self) -> String {
number_to_words(*self)
}
})*
};
}
// Implement `ToName` for common Rust unsigned integer types.
impl_to_name!(u8, u16, u32, u64);
// Implement `ToWordSequence` for common Rust unsigned integer types.
impl_to_word_sequence!(u8, u16, u32, u64);