thai_number_text/
lib.rs

1//! Thai Number Text - Convert numbers to Thai textual representations.
2//!
3//! A minimal, no_std-compatible crate for converting numbers to Thai text.
4//!
5//! # Capabilities
6//!
7//! - Integer and float conversion to Thai text
8//! - Thai Baht currency formatting
9//! - String input for arbitrarily large numbers (beyond i64)
10//! - Scientific notation support
11//! - Three เอ็ด modes: Colloquial, RoyalInstitute, Military
12//!
13//! # Feature Flags
14//!
15//! - `std`: Enables standard library support (for benchmarks/tests)
16//! - `serde`: Enables Serialize/Deserialize for types
17//!
18//! # Examples
19//!
20//! ```
21//! use thai_number_text::{to_text_i64, to_text_str, to_text_scientific, to_baht, ThaiTextOptions};
22//!
23//! let opts = ThaiTextOptions::new();
24//!
25//! // Integer conversion
26//! assert_eq!(to_text_i64(21, &opts), "ยี่สิบเอ็ด");
27//!
28//! // Currency
29//! assert_eq!(to_baht(100.50, &opts), "หนึ่งร้อยบาทห้าสิบสตางค์");
30//!
31//! // String input (supports arbitrarily large numbers)
32//! assert_eq!(to_text_str("1e6", &opts).unwrap(), "หนึ่งล้าน");
33//!
34//! // Scientific notation: 9.22 × 10^37
35//! assert_eq!(
36//!     to_text_scientific(9.22, 37, &opts),
37//!     "เก้าจุดสองสอง คูณ สิบยกกำลังสามสิบเจ็ด"
38//! );
39//! ```
40
41#![no_std]
42
43extern crate alloc;
44
45mod baht;
46mod bignum;
47mod convert;
48mod number;
49mod options;
50
51pub use bignum::{to_text_str, ParseError};
52pub use number::ThaiNumber;
53pub use options::{EtMode, ThaiTextOptions};
54
55use alloc::string::String;
56
57/// Converts an i64 to Thai text.
58///
59/// # Examples
60///
61/// ```
62/// use thai_number_text::{to_text_i64, ThaiTextOptions};
63///
64/// let opts = ThaiTextOptions::new();
65/// assert_eq!(to_text_i64(0, &opts), "ศูนย์");
66/// assert_eq!(to_text_i64(21, &opts), "ยี่สิบเอ็ด");
67/// assert_eq!(to_text_i64(101, &opts), "หนึ่งร้อยหนึ่ง"); // Colloquial: no เอ็ด
68/// ```
69#[inline]
70pub fn to_text_i64(n: i64, opts: &ThaiTextOptions) -> String {
71    convert::convert_i64(n, opts)
72}
73
74/// Converts an f64 to Thai text.
75///
76/// # Examples
77///
78/// ```
79/// use thai_number_text::{to_text_f64, ThaiTextOptions};
80///
81/// let opts = ThaiTextOptions::new();
82/// assert_eq!(to_text_f64(0.75, &opts), "ศูนย์จุดเจ็ดห้า");
83/// assert_eq!(to_text_f64(0.123, &opts), "ศูนย์จุดหนึ่งสองสาม");
84/// ```
85#[inline]
86pub fn to_text_f64(n: f64, opts: &ThaiTextOptions) -> String {
87    convert::convert_f64(n, opts)
88}
89
90/// Converts a number to Thai text (generic wrapper).
91///
92/// # Examples
93///
94/// ```
95/// use thai_number_text::{to_text, ThaiTextOptions};
96///
97/// let opts = ThaiTextOptions::new();
98/// assert_eq!(to_text(100, &opts), "หนึ่งร้อย");
99/// assert_eq!(to_text(0.5, &opts), "ศูนย์จุดห้า");
100/// ```
101#[inline]
102pub fn to_text<N: Into<ThaiNumber>>(n: N, opts: &ThaiTextOptions) -> String {
103    convert::convert_number(n.into(), opts)
104}
105
106/// Converts an amount to Thai Baht currency text.
107///
108/// # Examples
109///
110/// ```
111/// use thai_number_text::{to_baht, ThaiTextOptions};
112///
113/// let opts = ThaiTextOptions::new();
114/// assert_eq!(to_baht(100.0, &opts), "หนึ่งร้อยบาทถ้วน");
115/// assert_eq!(to_baht(100.50, &opts), "หนึ่งร้อยบาทห้าสิบสตางค์");
116/// ```
117#[inline]
118pub fn to_baht(amount: f64, opts: &ThaiTextOptions) -> String {
119    baht::convert_baht(amount, opts)
120}
121
122/// Converts a number in scientific notation to Thai text.
123///
124/// # Arguments
125/// * `mantissa` - The mantissa/significand (e.g., 9.22)
126/// * `exponent` - The exponent (e.g., 37 for 10^37)
127/// * `opts` - Conversion options
128///
129/// # Examples
130///
131/// ```
132/// use thai_number_text::{to_text_scientific, ThaiTextOptions};
133///
134/// let opts = ThaiTextOptions::new();
135/// // 9.22 x 10^37
136/// assert_eq!(
137///     to_text_scientific(9.22, 37, &opts),
138///     "เก้าจุดสองสอง คูณ สิบยกกำลังสามสิบเจ็ด"
139/// );
140/// // 1 x 10^6
141/// assert_eq!(
142///     to_text_scientific(1.0, 6, &opts),
143///     "หนึ่ง คูณ สิบยกกำลังหก"
144/// );
145/// ```
146#[inline]
147pub fn to_text_scientific(mantissa: f64, exponent: i64, opts: &ThaiTextOptions) -> String {
148    convert::convert_scientific(mantissa, exponent, opts)
149}
150
151#[cfg(test)]
152mod tests {
153    use super::*;
154
155    #[test]
156    fn test_integers() {
157        let opts = ThaiTextOptions::new();
158        assert_eq!(to_text_i64(0, &opts), "ศูนย์");
159        assert_eq!(to_text_i64(1, &opts), "หนึ่ง");
160        assert_eq!(to_text_i64(10, &opts), "สิบ");
161        assert_eq!(to_text_i64(11, &opts), "สิบเอ็ด");
162        assert_eq!(to_text_i64(20, &opts), "ยี่สิบ");
163        assert_eq!(to_text_i64(21, &opts), "ยี่สิบเอ็ด");
164        assert_eq!(to_text_i64(100, &opts), "หนึ่งร้อย");
165        assert_eq!(to_text_i64(101, &opts), "หนึ่งร้อยหนึ่ง"); // Colloquial: no เอ็ด
166        assert_eq!(to_text_i64(111, &opts), "หนึ่งร้อยสิบเอ็ด");
167        assert_eq!(to_text_i64(1000, &opts), "หนึ่งพัน");
168        assert_eq!(to_text_i64(1_000_000, &opts), "หนึ่งล้าน");
169    }
170
171    #[test]
172    fn test_floats() {
173        let opts = ThaiTextOptions::new();
174        assert_eq!(to_text_f64(0.5, &opts), "ศูนย์จุดห้า");
175        assert_eq!(to_text_f64(0.75, &opts), "ศูนย์จุดเจ็ดห้า");
176        assert_eq!(to_text_f64(0.123, &opts), "ศูนย์จุดหนึ่งสองสาม");
177    }
178
179    #[test]
180    fn test_baht() {
181        let opts = ThaiTextOptions::new();
182        assert_eq!(to_baht(100.0, &opts), "หนึ่งร้อยบาทถ้วน");
183        assert_eq!(to_baht(100.50, &opts), "หนึ่งร้อยบาทห้าสิบสตางค์");
184        assert_eq!(to_baht(0.75, &opts), "เจ็ดสิบห้าสตางค์");
185    }
186
187    #[test]
188    fn test_military_no_et() {
189        let opts = ThaiTextOptions::military();
190        assert_eq!(to_text_i64(11, &opts), "สิบหนึ่ง");
191        assert_eq!(to_text_i64(21, &opts), "ยี่สิบหนึ่ง");
192        assert_eq!(to_text_i64(101, &opts), "หนึ่งร้อยหนึ่ง");
193    }
194
195    #[test]
196    fn test_royal_institute_et() {
197        let opts = ThaiTextOptions::royal_institute();
198        assert_eq!(to_text_i64(101, &opts), "หนึ่งร้อยเอ็ด");
199        assert_eq!(to_text_i64(1001, &opts), "หนึ่งพันเอ็ด");
200    }
201
202    #[test]
203    fn test_accounting() {
204        let opts = ThaiTextOptions::accounting();
205        assert_eq!(to_baht(100.50, &opts), "หนึ่งร้อยบาทห้าสิบสตางค์ถ้วน");
206    }
207
208    #[test]
209    fn test_generic() {
210        let opts = ThaiTextOptions::new();
211        assert_eq!(to_text(100i32, &opts), "หนึ่งร้อย");
212        assert_eq!(to_text(0.5f64, &opts), "ศูนย์จุดห้า");
213    }
214
215    #[test]
216    fn test_large_numbers() {
217        let opts = ThaiTextOptions::new();
218        // Trillion (ล้านล้าน)
219        assert_eq!(to_text_i64(1_000_000_000_000, &opts), "หนึ่งล้านล้าน");
220        // Quintillion region (ล้านล้านล้าน)
221        let result = to_text_i64(i64::MAX, &opts);
222        assert!(result.contains("ล้านล้านล้าน"));
223    }
224
225    #[test]
226    fn test_string_conversion() {
227        let opts = ThaiTextOptions::new();
228        assert_eq!(to_text_str("21", &opts).unwrap(), "ยี่สิบเอ็ด");
229        assert_eq!(to_text_str("0.5", &opts).unwrap(), "ศูนย์จุดห้า");
230        assert_eq!(to_text_str("1e6", &opts).unwrap(), "หนึ่งล้าน");
231        // Beyond i64::MAX
232        let result = to_text_str("1000000000000000000000000", &opts).unwrap();
233        assert!(result.contains("ล้านล้านล้านล้าน"));
234    }
235
236    #[test]
237    fn test_scientific_notation() {
238        let opts = ThaiTextOptions::new();
239        assert_eq!(
240            to_text_scientific(9.22, 37, &opts),
241            "เก้าจุดสองสอง คูณ สิบยกกำลังสามสิบเจ็ด"
242        );
243        assert_eq!(
244            to_text_scientific(5.5, -3, &opts),
245            "ห้าจุดห้า คูณ สิบยกกำลังลบสาม"
246        );
247    }
248}