Rust
Lipi Lekhika offers a high-performance, type-safe transliteration library for Rust. All script data is embedded at compile time for zero runtime overhead.
The crate is no_std compatible by default: it uses alloc and does not require the Rust standard library, which suits WASM, embedded, and other constrained targets.
Installation
Section titled “Installation”The recommended way to install is using cargo add:
cargo add lipilekhikaBasic Usage
Section titled “Basic Usage”Transliteration
Section titled “Transliteration”The transliterate function is the primary API for converting text between scripts. It takes Script enum values and returns a Cow<str> directly (no Result).
use lipilekhika::{transliterate, Script};
fn main() { let result = transliterate( "na jAyatE mriyatE vA", Script::Normal, Script::Devanagari, None );
println!("{}", result); // न जायते म्रियते वा}Parameters:
text: &(impl AsRef<str> + ?Sized)— Text to transliteratefrom: Script— Source script/languageto: Script— Target script/languagetrans_options: Option<&CustomOptions>— Optional custom transliteration options
Returns: Cow<'a, str> — Transliterated text (borrows input when from == to)
With Custom Transliteration Options
Section titled “With Custom Transliteration Options”The fourth argument accepts a CustomOptions value. The recommended way to construct one is with CustomOptionsBuilder: call CustomOptionsBuilder::default(), enable options with <category>_<option>(bool) setters (replace : in canonical keys with _), then .build().
use lipilekhika::{transliterate, CustomOptionsBuilder, Script};
fn main() { let options = CustomOptionsBuilder::default() .brahmic_to_brahmic_replace_pancham_varga_varna_with_anusvAra(true) .build();
let result = transliterate( "गङ्गा", Script::Devanagari, Script::Gujarati, Some(&options), );
println!("{}", result); // ગંગા (instead of ગઙ્ગા)}From or to a hash map
Section titled “From or to a hash map”If your configuration already lives in a map (for example from JSON or another language binding), convert with CustomOptions::try_from_map and export with CustomOptions::to_options_map. Unknown keys return UnknownCustomOptionKey.
use lipilekhika::{transliterate, CustomOptions, Script};use std::collections::HashMap;
fn main() { let mut map = HashMap::new(); map.insert( "brahmic_to_brahmic:replace_pancham_varga_varna_with_anusvAra".to_string(), true, );
let options = CustomOptions::try_from_map(&map).unwrap(); let result = transliterate("गङ्गा", Script::Devanagari, Script::Gujarati, Some(&options)); println!("{}", result);
let exported: HashMap<String, bool> = options.to_options_map();}Script Enum
Section titled “Script Enum”All script/language parameters use the Script enum instead of raw strings. You can use full script names, language names, or shorthand aliases:
use lipilekhika::Script;
// Full script namesScript::DevanagariScript::TeluguScript::Normal // Romanized input scheme
// Language names (resolve to their script)Script::Hindi // → DevanagariScript::Sanskrit // → DevanagariScript::English // → NormalScript::Punjabi // → Gurumukhi
// Shorthand aliasesScript::Dev // → DevanagariScript::Tel // → TeluguScript::Tam // → TamilScript::Kan // → KannadaScript Display
Section titled “Script Display”Get the string representation using to_string():
use lipilekhika::Script;
let name = Script::Devanagari.to_string(); // "Devanagari"let alias = Script::Dev.to_string(); // "dev"Script Parsing
Section titled “Script Parsing”Parse a &str into a Script using FromStr (case-insensitive):
use std::str::FromStr;use lipilekhika::Script;
let script = Script::from_str("Devanagari").unwrap(); // Script::Devanagarilet script = Script::from_str("dev").unwrap(); // Script::Devlet script = Script::from_str("hindi").unwrap(); // Script::HindiResolved Script
Section titled “Resolved Script”Get the normalized/resolved script using .into() to convert a Script (which may be a language or alias) into the underlying ScriptListEnum:
use lipilekhika::{Script, ScriptListEnum};
let resolved: ScriptListEnum = Script::Hindi.into(); // ScriptListEnum::Devanagarilet resolved: ScriptListEnum = Script::Dev.into(); // ScriptListEnum::Devanagarilet resolved: ScriptListEnum = Script::English.into(); // ScriptListEnum::NormalUtility Functions
Section titled “Utility Functions”Getting Available Options
Section titled “Getting Available Options”Use get_all_options to discover which custom options are available for a specific script pair:
use lipilekhika::{get_all_options, Script};
fn main() { let options = get_all_options(Script::Devanagari, Script::Telugu);
for option in options { println!("Available option: {}", option); }}Parameters:
from_script: Script— Source scriptto_script: Script— Target script
Returns: Vec<String> — List of option keys
Getting Script List Data
Section titled “Getting Script List Data”Use get_script_list_data() to grab the cached script metadata that powers the transliteration helpers.
It returns a &'static ScriptListData containing the ordered script and language names plus the maps that translate between languages, scripts, and alternate aliases.
use lipilekhika::get_script_list_data;
fn main() { let data = get_script_list_data(); println!("Supported scripts: {:?}", data.scripts); println!("Language to script map: {:?}", data.lang_script_map);}Each call is zero-cost after the first because the data is stored in a OnceLock, so you can use it wherever you need to inspect available scripts or resolve language aliases.
Getting Typing Data
Section titled “Getting Typing Data”Use get_script_typing_data_map to get typing mappings for a script (useful for building custom input methods):
use lipilekhika::{get_script_typing_data_map, Script};
fn main() { let typing_data = get_script_typing_data_map(Script::Devanagari);
// Access common character mappings for (text, list_type, mappings) in &typing_data.common_krama_map { if !mappings.is_empty() { println!("{} can be typed using: {:?}", text, mappings); } }
// Access script-specific character mappings for (text, list_type, mappings) in &typing_data.script_specific_krama_map { if !mappings.is_empty() { println!("{} (script-specific) can be typed using: {:?}", text, mappings); } }}Parameters:
typing_script: Script— Script
Returns: ScriptTypingDataMap — Typing data containing:
common_krama_map— Mappings for common charactersscript_specific_krama_map— Mappings for script-specific characters
Each mapping is a tuple of (text: String, type: ListType, input_mappings: Vec<String>).
Typing Module
Section titled “Typing Module”For real-time character-by-character input, use the typing module which provides a stateful context for handling keyboard input.
Idle context clearing (std feature)
Section titled “Idle context clearing (std feature)”take_key_input/take_key_input_char: With the cratestdfeature enabled,take_key_input_charrecords wall-clock time between keys and may callclear_context()when the idle period exceedsauto_context_clear_time_ms.- Without
std: Timing fields are not compiled in; you must clear context explicitly (for example on focus loss or with your host’s own clock). clear_context()is always available regardless of features.
Enable timed auto-clear in your Cargo.toml:
lipilekhika = { version = "1.1", features = ["std"] }Basic Typing Context
Section titled “Basic Typing Context”use lipilekhika::Script;use lipilekhika::typing::{TypingContext, TypingContextOptions};
fn main() { let mut ctx = TypingContext::new(Script::Devanagari, None);
// Process character-by-character input let diff = ctx.take_key_input("n"); println!("Delete: {}, Add: '{}'", diff.to_delete_chars_count, diff.diff_add_text); // Output: Delete: 0, Add: 'न्'
let diff = ctx.take_key_input("a"); println!("Delete: {}, Add: '{}'", diff.to_delete_chars_count, diff.diff_add_text); // Output: Delete: 2, Add: 'न'
// Clear context when needed ctx.clear_context();}With Custom Options
Section titled “With Custom Options”use lipilekhika::Script;use lipilekhika::typing::{TypingContext, TypingContextOptions};
fn main() { let options = TypingContextOptions { auto_context_clear_time_ms: 3000, use_native_numerals: true, include_inherent_vowel: true, // For Hindi/Bengali style typing };
let mut ctx = TypingContext::new(Script::Devanagari, Some(options));
let diff = ctx.take_key_input("k"); println!("{}", diff.diff_add_text); // क (with inherent vowel)}Runtime Configuration
Section titled “Runtime Configuration”After creating a typing context, you can dynamically update typing options:
ctx.update_use_native_numerals(bool)- Enable/disable native numerals (e.g., १० instead of 10)ctx.update_include_inherent_vowel(bool)- Enable/disable inherent vowel inclusion (schwa deletion)ctx.get_use_native_numerals()- Get current native numerals settingctx.get_include_inherent_vowel()- Get current inherent vowel settingctx.get_normalized_script()- Get current normalized script name
Typing Module Types
Section titled “Typing Module Types”-
TypingContext— Stateful context for typing modenew(typing_script: Script, options: Option<TypingContextOptions>)— Create new contexttake_key_input(&mut self, key: &str)— Process single character inputclear_context(&mut self)— Clear internal state
-
TypingContextOptions— Configuration for typing behaviorauto_context_clear_time_ms: u64— Idle timeout for auto-clear (only when thestdfeature is enabled; default: 4500ms)use_native_numerals: bool— Use script-native numerals (default: true)include_inherent_vowel: bool— Include inherent vowel/schwa (default: false)
-
TypingDiff— Result of processing a key inputto_delete_chars_count: usize— Characters to delete from current statediff_add_text: String— Text to insert
-
ScriptTypingDataMap— Typing data for a scriptcommon_krama_map: Vec<TypingDataMapItem>— Common character mappingsscript_specific_krama_map: Vec<TypingDataMapItem>— Script-specific mappings
-
ListType— Character type enum:Anya,Vyanjana,Matra,Svara -
TypingDataMapItem— Type alias for(String, ListType, Vec<String>)
Performance Considerations
Section titled “Performance Considerations”- Embedded Data: All script data is embedded at compile time using
rust-embed, eliminating runtime file I/O - Static Lifetime: Script data is cached with
'staticlifetime for zero-cost access - Zero Allocations: The transliteration core minimizes allocations where possible
- Type Safety: Rust’s type system prevents common runtime errors
Error Handling
Section titled “Error Handling”Most APIs accept Script enum values directly and do not return Result. The only place where error handling is needed is when parsing a string into a Script:
use std::str::FromStr;use lipilekhika::Script;
match Script::from_str("InvalidScript") { Ok(script) => println!("Parsed: {:?}", script), Err(e) => eprintln!("Unknown script: {}", e),}Once you have a valid Script, all other functions (transliterate, get_all_options, TypingContext::new, etc.) are infallible.
Additional Resources
Section titled “Additional Resources”Next Steps
Section titled “Next Steps”- Explore custom transliteration options for fine-tuned control
- Check out supported scripts to see all available scripts
- Review real-time typing reference for advanced typing implementations