clnrm_template/functions/
mod.rs

1//! Custom Tera functions for clnrm templates
2//!
3//! Provides built-in functions for template rendering:
4//! - `env(name)` - Get environment variable
5//! - `now_rfc3339()` - Current timestamp (respects freeze_clock)
6//! - `sha256(s)` - SHA-256 hex digest
7//! - `toml_encode(value)` - Encode as TOML literal
8//! - `fake_name()` - Generate fake names for testing (test-only)
9//! - `fake_email()` - Generate fake emails for testing (test-only)
10//! - 50+ fake data generators for testing
11//! - Extended functions: UUIDs, collections, OTEL helpers, etc.
12
13pub mod extended;
14
15use crate::error::Result;
16use fake::Fake;
17use rand::rngs::StdRng;
18use rand::SeedableRng;
19use sha2::{Digest, Sha256};
20use std::collections::HashMap;
21use std::sync::Arc;
22use tera::{Function, Tera, Value};
23
24/// Register all custom functions with Tera
25///
26/// # Arguments
27/// * `tera` - Tera template engine
28/// * `determinism` - Optional determinism engine for reproducible rendering
29pub fn register_functions(
30    tera: &mut Tera,
31    determinism: Option<Arc<dyn TimestampProvider + Send + Sync>>,
32) -> Result<()> {
33    // Original functions
34    tera.register_function("env", EnvFunction);
35    tera.register_function("now_rfc3339", NowRfc3339Function::new(determinism.clone()));
36    tera.register_function("sha256", Sha256Function);
37    tera.register_function("toml_encode", TomlEncodeFunction);
38
39    // Fake data generators with determinism support
40    register_fake_data_functions(tera, determinism.clone());
41
42    // Extended functions (UUIDs, collections, OTEL, etc.)
43    extended::register_extended_functions(tera);
44
45    Ok(())
46}
47
48/// Trait for timestamp providers (for determinism support)
49pub trait TimestampProvider {
50    fn get_timestamp_rfc3339(&self) -> String;
51}
52
53/// Register all fake data generator functions
54fn register_fake_data_functions(
55    tera: &mut Tera,
56    _determinism: Option<Arc<dyn TimestampProvider + Send + Sync>>,
57) {
58    // UUIDs
59    tera.register_function("fake_uuid", FakeUuidFunction);
60    tera.register_function("fake_uuid_seeded", FakeUuidSeededFunction);
61
62    // Names
63    tera.register_function("fake_name", FakeNameFunction);
64    tera.register_function("fake_first_name", FakeFirstNameFunction);
65    tera.register_function("fake_last_name", FakeLastNameFunction);
66    tera.register_function("fake_title", FakeTitleFunction);
67    tera.register_function("fake_suffix", FakeSuffixFunction);
68
69    // Internet
70    tera.register_function("fake_email", FakeEmailFunction);
71    tera.register_function("fake_username", FakeUsernameFunction);
72    tera.register_function("fake_password", FakePasswordFunction);
73    tera.register_function("fake_domain", FakeDomainFunction);
74    tera.register_function("fake_url", FakeUrlFunction);
75    tera.register_function("fake_ipv4", FakeIpv4Function);
76    tera.register_function("fake_ipv6", FakeIpv6Function);
77    tera.register_function("fake_user_agent", FakeUserAgentFunction);
78    tera.register_function("fake_mac_address", FakeMacAddressFunction);
79
80    // Address
81    tera.register_function("fake_street", FakeStreetFunction);
82    tera.register_function("fake_city", FakeCityFunction);
83    tera.register_function("fake_state", FakeStateFunction);
84    tera.register_function("fake_zip", FakeZipFunction);
85    tera.register_function("fake_country", FakeCountryFunction);
86    tera.register_function("fake_latitude", FakeLatitudeFunction);
87    tera.register_function("fake_longitude", FakeLongitudeFunction);
88
89    // Phone
90    tera.register_function("fake_phone", FakePhoneFunction);
91    tera.register_function("fake_cell_phone", FakeCellPhoneFunction);
92
93    // Company
94    tera.register_function("fake_company", FakeCompanyFunction);
95    tera.register_function("fake_company_suffix", FakeCompanySuffixFunction);
96    tera.register_function("fake_industry", FakeIndustryFunction);
97    tera.register_function("fake_profession", FakeProfessionFunction);
98
99    // Lorem
100    tera.register_function("fake_word", FakeWordFunction);
101    tera.register_function("fake_words", FakeWordsFunction);
102    tera.register_function("fake_sentence", FakeSentenceFunction);
103    tera.register_function("fake_paragraph", FakeParagraphFunction);
104
105    // Numbers
106    tera.register_function("fake_int", FakeIntFunction);
107    tera.register_function("fake_int_range", FakeIntRangeFunction);
108    tera.register_function("fake_float", FakeFloatFunction);
109    tera.register_function("fake_bool", FakeBoolFunction);
110
111    // Dates & Times
112    tera.register_function("fake_date", FakeDateFunction);
113    tera.register_function("fake_time", FakeTimeFunction);
114    tera.register_function("fake_datetime", FakeDateTimeFunction);
115    tera.register_function("fake_timestamp", FakeTimestampFunction);
116
117    // Finance
118    tera.register_function("fake_credit_card", FakeCreditCardFunction);
119    tera.register_function("fake_currency_code", FakeCurrencyCodeFunction);
120    tera.register_function("fake_currency_name", FakeCurrencyNameFunction);
121    tera.register_function("fake_currency_symbol", FakeCurrencySymbolFunction);
122
123    // File & Path
124    tera.register_function("fake_filename", FakeFilenameFunction);
125    tera.register_function("fake_extension", FakeExtensionFunction);
126    tera.register_function("fake_mime_type", FakeMimeTypeFunction);
127    tera.register_function("fake_file_path", FakeFilePathFunction);
128
129    // Color
130    tera.register_function("fake_color", FakeColorFunction);
131    tera.register_function("fake_hex_color", FakeHexColorFunction);
132    tera.register_function("fake_rgb_color", FakeRgbColorFunction);
133
134    // Misc
135    tera.register_function("fake_string", FakeStringFunction);
136    tera.register_function("fake_port", FakePortFunction);
137    tera.register_function("fake_semver", FakeSemverFunction);
138}
139
140/// env(name) - Get environment variable
141///
142/// Usage: `{{ env(name="HOME") }}`
143struct EnvFunction;
144
145impl Function for EnvFunction {
146    fn call(&self, args: &HashMap<String, Value>) -> tera::Result<Value> {
147        let name = args
148            .get("name")
149            .and_then(|v| v.as_str())
150            .ok_or_else(|| tera::Error::msg("env() requires 'name' parameter"))?;
151
152        std::env::var(name)
153            .map(Value::String)
154            .map_err(|_| tera::Error::msg(format!("Environment variable '{}' not found", name)))
155    }
156}
157
158/// now_rfc3339() - Current timestamp (respects freeze_clock)
159///
160/// Usage: `{{ now_rfc3339() }}`
161///
162/// Returns RFC3339 formatted timestamp. Can be frozen for deterministic tests.
163struct NowRfc3339Function {
164    provider: Option<Arc<dyn TimestampProvider + Send + Sync>>,
165}
166
167impl NowRfc3339Function {
168    fn new(provider: Option<Arc<dyn TimestampProvider + Send + Sync>>) -> Self {
169        Self { provider }
170    }
171}
172
173impl Function for NowRfc3339Function {
174    fn call(&self, _args: &HashMap<String, Value>) -> tera::Result<Value> {
175        if let Some(ref provider) = self.provider {
176            Ok(Value::String(provider.get_timestamp_rfc3339()))
177        } else {
178            Ok(Value::String(chrono::Utc::now().to_rfc3339()))
179        }
180    }
181}
182
183/// sha256(s) - SHA-256 hex digest
184///
185/// Usage: `{{ sha256(s="hello") }}`
186struct Sha256Function;
187
188impl Function for Sha256Function {
189    fn call(&self, args: &HashMap<String, Value>) -> tera::Result<Value> {
190        let input = args
191            .get("s")
192            .and_then(|v| v.as_str())
193            .ok_or_else(|| tera::Error::msg("sha256() requires 's' parameter"))?;
194
195        let mut hasher = Sha256::new();
196        hasher.update(input.as_bytes());
197        let result = hasher.finalize();
198
199        Ok(Value::String(format!("{:x}", result)))
200    }
201}
202
203/// toml_encode(value) - Encode as TOML literal
204///
205/// Usage: `{{ toml_encode(value=vars.myvar) }}`
206struct TomlEncodeFunction;
207
208impl Function for TomlEncodeFunction {
209    fn call(&self, args: &HashMap<String, Value>) -> tera::Result<Value> {
210        let value = args
211            .get("value")
212            .ok_or_else(|| tera::Error::msg("toml_encode() requires 'value' parameter"))?;
213
214        // Convert JSON value to TOML string
215        let toml_str = match value {
216            Value::String(s) => format!("\"{}\"", s.replace('\"', "\\\"")),
217            Value::Number(n) => n.to_string(),
218            Value::Bool(b) => b.to_string(),
219            Value::Array(arr) => {
220                let items: Vec<String> = arr
221                    .iter()
222                    .map(|v| match v {
223                        Value::String(s) => format!("\"{}\"", s.replace('\"', "\\\"")),
224                        _ => v.to_string(),
225                    })
226                    .collect();
227                format!("[{}]", items.join(","))
228            }
229            Value::Object(obj) => {
230                let items: Vec<String> = obj
231                    .iter()
232                    .map(|(k, v)| match v {
233                        Value::String(s) => {
234                            format!("\"{}\"=\"{}\"", k, s.replace('\"', "\\\""))
235                        }
236                        _ => format!("\"{}\"={}", k, v),
237                    })
238                    .collect();
239                format!("{{{}}}", items.join(","))
240            }
241            Value::Null => "null".to_string(),
242        };
243
244        Ok(Value::String(toml_str))
245    }
246}
247
248// ========================================
249// Fake Data Generator Functions (50+)
250// ========================================
251
252// Helper to get seed from args
253fn get_seed(args: &HashMap<String, Value>) -> u64 {
254    args.get("seed")
255        .and_then(|v| v.as_u64())
256        .unwrap_or_else(rand::random)
257}
258
259// === UUIDs ===
260
261/// fake_uuid() - Generate random UUID v4
262struct FakeUuidFunction;
263impl Function for FakeUuidFunction {
264    fn call(&self, _args: &HashMap<String, Value>) -> tera::Result<Value> {
265        Ok(Value::String(uuid::Uuid::new_v4().to_string()))
266    }
267}
268
269/// fake_uuid_seeded(seed=42) - Generate deterministic UUID from seed
270struct FakeUuidSeededFunction;
271impl Function for FakeUuidSeededFunction {
272    fn call(&self, args: &HashMap<String, Value>) -> tera::Result<Value> {
273        let seed = get_seed(args);
274        // Generate deterministic UUID from seed
275        let uuid_bytes = format!("{:032x}", seed);
276        Ok(Value::String(format!(
277            "{}-{}-{}-{}-{}",
278            &uuid_bytes[0..8],
279            &uuid_bytes[8..12],
280            &uuid_bytes[12..16],
281            &uuid_bytes[16..20],
282            &uuid_bytes[20..32]
283        )))
284    }
285}
286
287// === Names ===
288
289/// fake_name() - Generate full name
290struct FakeNameFunction;
291impl Function for FakeNameFunction {
292    fn call(&self, args: &HashMap<String, Value>) -> tera::Result<Value> {
293        use fake::faker::name::en::Name;
294        let seed = get_seed(args);
295        let mut rng = StdRng::seed_from_u64(seed);
296        Ok(Value::String(Name().fake_with_rng(&mut rng)))
297    }
298}
299
300/// fake_first_name() - Generate first name
301struct FakeFirstNameFunction;
302impl Function for FakeFirstNameFunction {
303    fn call(&self, args: &HashMap<String, Value>) -> tera::Result<Value> {
304        use fake::faker::name::en::FirstName;
305        let seed = get_seed(args);
306        let mut rng = StdRng::seed_from_u64(seed);
307        Ok(Value::String(FirstName().fake_with_rng(&mut rng)))
308    }
309}
310
311/// fake_last_name() - Generate last name
312struct FakeLastNameFunction;
313impl Function for FakeLastNameFunction {
314    fn call(&self, args: &HashMap<String, Value>) -> tera::Result<Value> {
315        use fake::faker::name::en::LastName;
316        let seed = get_seed(args);
317        let mut rng = StdRng::seed_from_u64(seed);
318        Ok(Value::String(LastName().fake_with_rng(&mut rng)))
319    }
320}
321
322/// fake_title() - Generate name title (Mr., Mrs., etc.)
323struct FakeTitleFunction;
324impl Function for FakeTitleFunction {
325    fn call(&self, args: &HashMap<String, Value>) -> tera::Result<Value> {
326        use fake::faker::name::en::Title;
327        let seed = get_seed(args);
328        let mut rng = StdRng::seed_from_u64(seed);
329        Ok(Value::String(Title().fake_with_rng(&mut rng)))
330    }
331}
332
333/// fake_suffix() - Generate name suffix (Jr., Sr., etc.)
334struct FakeSuffixFunction;
335impl Function for FakeSuffixFunction {
336    fn call(&self, args: &HashMap<String, Value>) -> tera::Result<Value> {
337        use fake::faker::name::en::Suffix;
338        let seed = get_seed(args);
339        let mut rng = StdRng::seed_from_u64(seed);
340        Ok(Value::String(Suffix().fake_with_rng(&mut rng)))
341    }
342}
343
344// === Internet ===
345
346/// fake_email() - Generate email address
347struct FakeEmailFunction;
348impl Function for FakeEmailFunction {
349    fn call(&self, args: &HashMap<String, Value>) -> tera::Result<Value> {
350        use fake::faker::internet::en::SafeEmail;
351        let seed = get_seed(args);
352        let mut rng = StdRng::seed_from_u64(seed);
353        Ok(Value::String(SafeEmail().fake_with_rng(&mut rng)))
354    }
355}
356
357/// fake_username() - Generate username
358struct FakeUsernameFunction;
359impl Function for FakeUsernameFunction {
360    fn call(&self, args: &HashMap<String, Value>) -> tera::Result<Value> {
361        use fake::faker::internet::en::Username;
362        let seed = get_seed(args);
363        let mut rng = StdRng::seed_from_u64(seed);
364        Ok(Value::String(Username().fake_with_rng(&mut rng)))
365    }
366}
367
368/// fake_password(min=8, max=20) - Generate password
369struct FakePasswordFunction;
370impl Function for FakePasswordFunction {
371    fn call(&self, args: &HashMap<String, Value>) -> tera::Result<Value> {
372        use fake::faker::internet::en::Password;
373        let seed = get_seed(args);
374        let mut rng = StdRng::seed_from_u64(seed);
375        let min = args.get("min").and_then(|v| v.as_u64()).unwrap_or(8) as usize;
376        let max = args.get("max").and_then(|v| v.as_u64()).unwrap_or(20) as usize;
377        Ok(Value::String(Password(min..max).fake_with_rng(&mut rng)))
378    }
379}
380
381/// fake_domain() - Generate domain name
382struct FakeDomainFunction;
383impl Function for FakeDomainFunction {
384    fn call(&self, args: &HashMap<String, Value>) -> tera::Result<Value> {
385        use fake::faker::internet::en::DomainSuffix;
386        use fake::faker::lorem::en::Word;
387        let seed = get_seed(args);
388        let mut rng = StdRng::seed_from_u64(seed);
389        let word: String = Word().fake_with_rng(&mut rng);
390        let suffix: String = DomainSuffix().fake_with_rng(&mut rng);
391        Ok(Value::String(format!("{}.{}", word, suffix)))
392    }
393}
394
395/// fake_url() - Generate URL
396struct FakeUrlFunction;
397impl Function for FakeUrlFunction {
398    fn call(&self, args: &HashMap<String, Value>) -> tera::Result<Value> {
399        use fake::faker::internet::en::DomainSuffix;
400        use fake::faker::lorem::en::Word;
401        let seed = get_seed(args);
402        let mut rng = StdRng::seed_from_u64(seed);
403        let word: String = Word().fake_with_rng(&mut rng);
404        let suffix: String = DomainSuffix().fake_with_rng(&mut rng);
405        Ok(Value::String(format!("https://{}.{}", word, suffix)))
406    }
407}
408
409/// fake_ipv4() - Generate IPv4 address
410struct FakeIpv4Function;
411impl Function for FakeIpv4Function {
412    fn call(&self, args: &HashMap<String, Value>) -> tera::Result<Value> {
413        use fake::faker::internet::en::IPv4;
414        use fake::Fake;
415        let seed = get_seed(args);
416        let mut rng = StdRng::seed_from_u64(seed);
417        let ip: std::net::Ipv4Addr = IPv4().fake_with_rng::<std::net::Ipv4Addr, _>(&mut rng);
418        Ok(Value::String(ip.to_string()))
419    }
420}
421
422/// fake_ipv6() - Generate IPv6 address
423struct FakeIpv6Function;
424impl Function for FakeIpv6Function {
425    fn call(&self, args: &HashMap<String, Value>) -> tera::Result<Value> {
426        use fake::faker::internet::en::IPv6;
427        use fake::Fake;
428        let seed = get_seed(args);
429        let mut rng = StdRng::seed_from_u64(seed);
430        let ip: std::net::Ipv6Addr = IPv6().fake_with_rng::<std::net::Ipv6Addr, _>(&mut rng);
431        Ok(Value::String(ip.to_string()))
432    }
433}
434
435/// fake_user_agent() - Generate user agent string
436struct FakeUserAgentFunction;
437impl Function for FakeUserAgentFunction {
438    fn call(&self, args: &HashMap<String, Value>) -> tera::Result<Value> {
439        use fake::faker::internet::en::UserAgent;
440        let seed = get_seed(args);
441        let mut rng = StdRng::seed_from_u64(seed);
442        Ok(Value::String(UserAgent().fake_with_rng(&mut rng)))
443    }
444}
445
446/// fake_mac_address() - Generate MAC address
447struct FakeMacAddressFunction;
448impl Function for FakeMacAddressFunction {
449    fn call(&self, args: &HashMap<String, Value>) -> tera::Result<Value> {
450        use fake::faker::internet::en::MACAddress;
451        let seed = get_seed(args);
452        let mut rng = StdRng::seed_from_u64(seed);
453        Ok(Value::String(MACAddress().fake_with_rng(&mut rng)))
454    }
455}
456
457// === Address ===
458
459/// fake_street() - Generate street address
460struct FakeStreetFunction;
461impl Function for FakeStreetFunction {
462    fn call(&self, args: &HashMap<String, Value>) -> tera::Result<Value> {
463        use fake::faker::address::en::StreetName;
464        let seed = get_seed(args);
465        let mut rng = StdRng::seed_from_u64(seed);
466        Ok(Value::String(StreetName().fake_with_rng(&mut rng)))
467    }
468}
469
470/// fake_city() - Generate city name
471struct FakeCityFunction;
472impl Function for FakeCityFunction {
473    fn call(&self, args: &HashMap<String, Value>) -> tera::Result<Value> {
474        use fake::faker::address::en::CityName;
475        let seed = get_seed(args);
476        let mut rng = StdRng::seed_from_u64(seed);
477        Ok(Value::String(CityName().fake_with_rng(&mut rng)))
478    }
479}
480
481/// fake_state() - Generate state name
482struct FakeStateFunction;
483impl Function for FakeStateFunction {
484    fn call(&self, args: &HashMap<String, Value>) -> tera::Result<Value> {
485        use fake::faker::address::en::StateName;
486        let seed = get_seed(args);
487        let mut rng = StdRng::seed_from_u64(seed);
488        Ok(Value::String(StateName().fake_with_rng(&mut rng)))
489    }
490}
491
492/// fake_zip() - Generate ZIP code
493struct FakeZipFunction;
494impl Function for FakeZipFunction {
495    fn call(&self, args: &HashMap<String, Value>) -> tera::Result<Value> {
496        use fake::faker::address::en::ZipCode;
497        let seed = get_seed(args);
498        let mut rng = StdRng::seed_from_u64(seed);
499        Ok(Value::String(ZipCode().fake_with_rng(&mut rng)))
500    }
501}
502
503/// fake_country() - Generate country name
504struct FakeCountryFunction;
505impl Function for FakeCountryFunction {
506    fn call(&self, args: &HashMap<String, Value>) -> tera::Result<Value> {
507        use fake::faker::address::en::CountryName;
508        let seed = get_seed(args);
509        let mut rng = StdRng::seed_from_u64(seed);
510        Ok(Value::String(CountryName().fake_with_rng(&mut rng)))
511    }
512}
513
514/// fake_latitude() - Generate latitude
515struct FakeLatitudeFunction;
516impl Function for FakeLatitudeFunction {
517    fn call(&self, args: &HashMap<String, Value>) -> tera::Result<Value> {
518        use fake::faker::address::en::Latitude;
519        let seed = get_seed(args);
520        let mut rng = StdRng::seed_from_u64(seed);
521        Ok(Value::String(Latitude().fake_with_rng(&mut rng)))
522    }
523}
524
525/// fake_longitude() - Generate longitude
526struct FakeLongitudeFunction;
527impl Function for FakeLongitudeFunction {
528    fn call(&self, args: &HashMap<String, Value>) -> tera::Result<Value> {
529        use fake::faker::address::en::Longitude;
530        let seed = get_seed(args);
531        let mut rng = StdRng::seed_from_u64(seed);
532        Ok(Value::String(Longitude().fake_with_rng(&mut rng)))
533    }
534}
535
536// === Phone ===
537
538/// fake_phone() - Generate phone number
539struct FakePhoneFunction;
540impl Function for FakePhoneFunction {
541    fn call(&self, args: &HashMap<String, Value>) -> tera::Result<Value> {
542        use fake::faker::phone_number::en::PhoneNumber;
543        let seed = get_seed(args);
544        let mut rng = StdRng::seed_from_u64(seed);
545        Ok(Value::String(PhoneNumber().fake_with_rng(&mut rng)))
546    }
547}
548
549/// fake_cell_phone() - Generate cell phone number
550struct FakeCellPhoneFunction;
551impl Function for FakeCellPhoneFunction {
552    fn call(&self, args: &HashMap<String, Value>) -> tera::Result<Value> {
553        use fake::faker::phone_number::en::CellNumber;
554        let seed = get_seed(args);
555        let mut rng = StdRng::seed_from_u64(seed);
556        Ok(Value::String(CellNumber().fake_with_rng(&mut rng)))
557    }
558}
559
560// === Company ===
561
562/// fake_company() - Generate company name
563struct FakeCompanyFunction;
564impl Function for FakeCompanyFunction {
565    fn call(&self, args: &HashMap<String, Value>) -> tera::Result<Value> {
566        use fake::faker::company::en::CompanyName;
567        let seed = get_seed(args);
568        let mut rng = StdRng::seed_from_u64(seed);
569        Ok(Value::String(CompanyName().fake_with_rng(&mut rng)))
570    }
571}
572
573/// fake_company_suffix() - Generate company suffix (Inc., LLC, etc.)
574struct FakeCompanySuffixFunction;
575impl Function for FakeCompanySuffixFunction {
576    fn call(&self, args: &HashMap<String, Value>) -> tera::Result<Value> {
577        use fake::faker::company::en::CompanySuffix;
578        let seed = get_seed(args);
579        let mut rng = StdRng::seed_from_u64(seed);
580        Ok(Value::String(CompanySuffix().fake_with_rng(&mut rng)))
581    }
582}
583
584/// fake_industry() - Generate industry name
585struct FakeIndustryFunction;
586impl Function for FakeIndustryFunction {
587    fn call(&self, args: &HashMap<String, Value>) -> tera::Result<Value> {
588        use fake::faker::company::en::Industry;
589        let seed = get_seed(args);
590        let mut rng = StdRng::seed_from_u64(seed);
591        Ok(Value::String(Industry().fake_with_rng(&mut rng)))
592    }
593}
594
595/// fake_profession() - Generate profession
596struct FakeProfessionFunction;
597impl Function for FakeProfessionFunction {
598    fn call(&self, args: &HashMap<String, Value>) -> tera::Result<Value> {
599        use fake::faker::company::en::Profession;
600        let seed = get_seed(args);
601        let mut rng = StdRng::seed_from_u64(seed);
602        Ok(Value::String(Profession().fake_with_rng(&mut rng)))
603    }
604}
605
606// === Lorem ===
607
608/// fake_word() - Generate random word
609struct FakeWordFunction;
610impl Function for FakeWordFunction {
611    fn call(&self, args: &HashMap<String, Value>) -> tera::Result<Value> {
612        use fake::faker::lorem::en::Word;
613        let seed = get_seed(args);
614        let mut rng = StdRng::seed_from_u64(seed);
615        Ok(Value::String(Word().fake_with_rng(&mut rng)))
616    }
617}
618
619/// fake_words(count=3) - Generate multiple words
620struct FakeWordsFunction;
621impl Function for FakeWordsFunction {
622    fn call(&self, args: &HashMap<String, Value>) -> tera::Result<Value> {
623        use fake::faker::lorem::en::Words;
624        let seed = get_seed(args);
625        let mut rng = StdRng::seed_from_u64(seed);
626        let count = args.get("count").and_then(|v| v.as_u64()).unwrap_or(3) as usize;
627        let words: Vec<String> = Words(count..count + 1).fake_with_rng(&mut rng);
628        Ok(Value::String(words.join(" ")))
629    }
630}
631
632/// fake_sentence() - Generate sentence
633struct FakeSentenceFunction;
634impl Function for FakeSentenceFunction {
635    fn call(&self, args: &HashMap<String, Value>) -> tera::Result<Value> {
636        use fake::faker::lorem::en::Sentence;
637        let seed = get_seed(args);
638        let mut rng = StdRng::seed_from_u64(seed);
639        let min = args.get("min").and_then(|v| v.as_u64()).unwrap_or(4) as usize;
640        let max = args.get("max").and_then(|v| v.as_u64()).unwrap_or(10) as usize;
641        Ok(Value::String(Sentence(min..max).fake_with_rng(&mut rng)))
642    }
643}
644
645/// fake_paragraph() - Generate paragraph
646struct FakeParagraphFunction;
647impl Function for FakeParagraphFunction {
648    fn call(&self, args: &HashMap<String, Value>) -> tera::Result<Value> {
649        use fake::faker::lorem::en::Paragraph;
650        let seed = get_seed(args);
651        let mut rng = StdRng::seed_from_u64(seed);
652        let min = args.get("min").and_then(|v| v.as_u64()).unwrap_or(3) as usize;
653        let max = args.get("max").and_then(|v| v.as_u64()).unwrap_or(7) as usize;
654        Ok(Value::String(Paragraph(min..max).fake_with_rng(&mut rng)))
655    }
656}
657
658// === Numbers ===
659
660/// fake_int() - Generate random integer
661struct FakeIntFunction;
662impl Function for FakeIntFunction {
663    fn call(&self, args: &HashMap<String, Value>) -> tera::Result<Value> {
664        let seed = get_seed(args);
665        let mut rng = StdRng::seed_from_u64(seed);
666        let value: i32 = (0..1000).fake_with_rng(&mut rng);
667        Ok(Value::Number(value.into()))
668    }
669}
670
671/// fake_int_range(min=0, max=100) - Generate integer in range
672struct FakeIntRangeFunction;
673impl Function for FakeIntRangeFunction {
674    fn call(&self, args: &HashMap<String, Value>) -> tera::Result<Value> {
675        let seed = get_seed(args);
676        let mut rng = StdRng::seed_from_u64(seed);
677        let min = args.get("min").and_then(|v| v.as_i64()).unwrap_or(0) as i32;
678        let max = args.get("max").and_then(|v| v.as_i64()).unwrap_or(100) as i32;
679        let value: i32 = (min..max).fake_with_rng(&mut rng);
680        Ok(Value::Number(value.into()))
681    }
682}
683
684/// fake_float() - Generate random float
685struct FakeFloatFunction;
686impl Function for FakeFloatFunction {
687    fn call(&self, args: &HashMap<String, Value>) -> tera::Result<Value> {
688        let seed = get_seed(args);
689        let mut rng = StdRng::seed_from_u64(seed);
690        let value: f64 = (0.0..1000.0).fake_with_rng(&mut rng);
691        Ok(Value::Number(
692            serde_json::Number::from_f64(value).unwrap_or(serde_json::Number::from(0)),
693        ))
694    }
695}
696
697/// fake_bool() - Generate random boolean
698struct FakeBoolFunction;
699impl Function for FakeBoolFunction {
700    fn call(&self, args: &HashMap<String, Value>) -> tera::Result<Value> {
701        use fake::faker::boolean::en::Boolean;
702        let seed = get_seed(args);
703        let mut rng = StdRng::seed_from_u64(seed);
704        let ratio = args.get("ratio").and_then(|v| v.as_u64()).unwrap_or(50) as u8;
705        Ok(Value::Bool(Boolean(ratio).fake_with_rng(&mut rng)))
706    }
707}
708
709// === Dates & Times ===
710
711/// fake_date() - Generate date string
712struct FakeDateFunction;
713impl Function for FakeDateFunction {
714    fn call(&self, args: &HashMap<String, Value>) -> tera::Result<Value> {
715        use fake::faker::chrono::en::Date;
716        let seed = get_seed(args);
717        let mut rng = StdRng::seed_from_u64(seed);
718        let date: chrono::NaiveDate = Date().fake_with_rng(&mut rng);
719        Ok(Value::String(date.to_string()))
720    }
721}
722
723/// fake_time() - Generate time string
724struct FakeTimeFunction;
725impl Function for FakeTimeFunction {
726    fn call(&self, args: &HashMap<String, Value>) -> tera::Result<Value> {
727        use fake::faker::chrono::en::Time;
728        let seed = get_seed(args);
729        let mut rng = StdRng::seed_from_u64(seed);
730        let time: chrono::NaiveTime = Time().fake_with_rng(&mut rng);
731        Ok(Value::String(time.to_string()))
732    }
733}
734
735/// fake_datetime() - Generate datetime string
736struct FakeDateTimeFunction;
737impl Function for FakeDateTimeFunction {
738    fn call(&self, args: &HashMap<String, Value>) -> tera::Result<Value> {
739        use fake::faker::chrono::en::DateTime;
740        let seed = get_seed(args);
741        let mut rng = StdRng::seed_from_u64(seed);
742        let dt: chrono::DateTime<chrono::Utc> = DateTime().fake_with_rng(&mut rng);
743        Ok(Value::String(dt.to_rfc3339()))
744    }
745}
746
747/// fake_timestamp() - Generate Unix timestamp
748struct FakeTimestampFunction;
749impl Function for FakeTimestampFunction {
750    fn call(&self, args: &HashMap<String, Value>) -> tera::Result<Value> {
751        use fake::faker::chrono::en::DateTime;
752        let seed = get_seed(args);
753        let mut rng = StdRng::seed_from_u64(seed);
754        let dt: chrono::DateTime<chrono::Utc> = DateTime().fake_with_rng(&mut rng);
755        Ok(Value::Number(dt.timestamp().into()))
756    }
757}
758
759// === Finance ===
760
761/// fake_credit_card() - Generate credit card number
762struct FakeCreditCardFunction;
763impl Function for FakeCreditCardFunction {
764    fn call(&self, args: &HashMap<String, Value>) -> tera::Result<Value> {
765        use fake::faker::creditcard::en::CreditCardNumber;
766        let seed = get_seed(args);
767        let mut rng = StdRng::seed_from_u64(seed);
768        Ok(Value::String(CreditCardNumber().fake_with_rng(&mut rng)))
769    }
770}
771
772/// fake_currency_code() - Generate currency code (USD, EUR, etc.)
773struct FakeCurrencyCodeFunction;
774impl Function for FakeCurrencyCodeFunction {
775    fn call(&self, args: &HashMap<String, Value>) -> tera::Result<Value> {
776        use fake::faker::currency::en::CurrencyCode;
777        let seed = get_seed(args);
778        let mut rng = StdRng::seed_from_u64(seed);
779        Ok(Value::String(CurrencyCode().fake_with_rng(&mut rng)))
780    }
781}
782
783/// fake_currency_name() - Generate currency name
784struct FakeCurrencyNameFunction;
785impl Function for FakeCurrencyNameFunction {
786    fn call(&self, args: &HashMap<String, Value>) -> tera::Result<Value> {
787        use fake::faker::currency::en::CurrencyName;
788        let seed = get_seed(args);
789        let mut rng = StdRng::seed_from_u64(seed);
790        Ok(Value::String(CurrencyName().fake_with_rng(&mut rng)))
791    }
792}
793
794/// fake_currency_symbol() - Generate currency symbol ($, €, etc.)
795struct FakeCurrencySymbolFunction;
796impl Function for FakeCurrencySymbolFunction {
797    fn call(&self, args: &HashMap<String, Value>) -> tera::Result<Value> {
798        use fake::faker::currency::en::CurrencySymbol;
799        let seed = get_seed(args);
800        let mut rng = StdRng::seed_from_u64(seed);
801        Ok(Value::String(CurrencySymbol().fake_with_rng(&mut rng)))
802    }
803}
804
805// === File & Path ===
806
807/// fake_filename() - Generate filename
808struct FakeFilenameFunction;
809impl Function for FakeFilenameFunction {
810    fn call(&self, args: &HashMap<String, Value>) -> tera::Result<Value> {
811        use fake::faker::filesystem::en::FileName;
812        let seed = get_seed(args);
813        let mut rng = StdRng::seed_from_u64(seed);
814        Ok(Value::String(FileName().fake_with_rng(&mut rng)))
815    }
816}
817
818/// fake_extension() - Generate file extension
819struct FakeExtensionFunction;
820impl Function for FakeExtensionFunction {
821    fn call(&self, args: &HashMap<String, Value>) -> tera::Result<Value> {
822        use fake::faker::filesystem::en::FileExtension;
823        let seed = get_seed(args);
824        let mut rng = StdRng::seed_from_u64(seed);
825        Ok(Value::String(FileExtension().fake_with_rng(&mut rng)))
826    }
827}
828
829/// fake_mime_type() - Generate MIME type
830struct FakeMimeTypeFunction;
831impl Function for FakeMimeTypeFunction {
832    fn call(&self, args: &HashMap<String, Value>) -> tera::Result<Value> {
833        use fake::faker::filesystem::en::MimeType;
834        let seed = get_seed(args);
835        let mut rng = StdRng::seed_from_u64(seed);
836        Ok(Value::String(MimeType().fake_with_rng(&mut rng)))
837    }
838}
839
840/// fake_file_path() - Generate file path
841struct FakeFilePathFunction;
842impl Function for FakeFilePathFunction {
843    fn call(&self, args: &HashMap<String, Value>) -> tera::Result<Value> {
844        use fake::faker::filesystem::en::FilePath;
845        let seed = get_seed(args);
846        let mut rng = StdRng::seed_from_u64(seed);
847        Ok(Value::String(FilePath().fake_with_rng(&mut rng)))
848    }
849}
850
851// === Color ===
852
853/// fake_color() - Generate color name
854struct FakeColorFunction;
855impl Function for FakeColorFunction {
856    fn call(&self, args: &HashMap<String, Value>) -> tera::Result<Value> {
857        use fake::faker::color::en::Color;
858        let seed = get_seed(args);
859        let mut rng = StdRng::seed_from_u64(seed);
860        Ok(Value::String(Color().fake_with_rng(&mut rng)))
861    }
862}
863
864/// fake_hex_color() - Generate hex color code
865struct FakeHexColorFunction;
866impl Function for FakeHexColorFunction {
867    fn call(&self, args: &HashMap<String, Value>) -> tera::Result<Value> {
868        use fake::faker::color::en::HexColor;
869        let seed = get_seed(args);
870        let mut rng = StdRng::seed_from_u64(seed);
871        Ok(Value::String(HexColor().fake_with_rng(&mut rng)))
872    }
873}
874
875/// fake_rgb_color() - Generate RGB color
876struct FakeRgbColorFunction;
877impl Function for FakeRgbColorFunction {
878    fn call(&self, args: &HashMap<String, Value>) -> tera::Result<Value> {
879        use fake::faker::color::en::RgbColor;
880        let seed = get_seed(args);
881        let mut rng = StdRng::seed_from_u64(seed);
882        Ok(Value::String(RgbColor().fake_with_rng(&mut rng)))
883    }
884}
885
886// === Misc ===
887
888/// fake_string(len=10) - Generate random string
889struct FakeStringFunction;
890impl Function for FakeStringFunction {
891    fn call(&self, args: &HashMap<String, Value>) -> tera::Result<Value> {
892        use rand::Rng;
893        let seed = get_seed(args);
894        let mut rng = StdRng::seed_from_u64(seed);
895        let len = args.get("len").and_then(|v| v.as_u64()).unwrap_or(10) as usize;
896        let s: String = (0..len)
897            .map(|_| rng.gen_range(b'a'..=b'z') as char)
898            .collect();
899        Ok(Value::String(s))
900    }
901}
902
903/// fake_port() - Generate port number
904struct FakePortFunction;
905impl Function for FakePortFunction {
906    fn call(&self, args: &HashMap<String, Value>) -> tera::Result<Value> {
907        let seed = get_seed(args);
908        let mut rng = StdRng::seed_from_u64(seed);
909        let port: u16 = (1024..65535).fake_with_rng(&mut rng);
910        Ok(Value::Number(port.into()))
911    }
912}
913
914/// fake_semver() - Generate semantic version
915struct FakeSemverFunction;
916impl Function for FakeSemverFunction {
917    fn call(&self, args: &HashMap<String, Value>) -> tera::Result<Value> {
918        let seed = get_seed(args);
919        let mut rng = StdRng::seed_from_u64(seed);
920        let major: u8 = (0..10).fake_with_rng(&mut rng);
921        let minor: u8 = (0..20).fake_with_rng(&mut rng);
922        let patch: u8 = (0..100).fake_with_rng(&mut rng);
923        Ok(Value::String(format!("{}.{}.{}", major, minor, patch)))
924    }
925}