rust_rule_engine/engine/
engine.rs

1use crate::engine::{facts::Facts, knowledge_base::KnowledgeBase};
2use crate::errors::{Result, RuleEngineError};
3use crate::types::{ActionType, Value};
4use std::collections::HashMap;
5use std::time::{Duration, Instant};
6
7/// Type for custom function implementations
8pub type CustomFunction = Box<dyn Fn(&[Value], &Facts) -> Result<Value> + Send + Sync>;
9
10/// Configuration options for the rule engine
11#[derive(Debug, Clone)]
12pub struct EngineConfig {
13    /// Maximum number of execution cycles
14    pub max_cycles: usize,
15    /// Execution timeout
16    pub timeout: Option<Duration>,
17    /// Enable performance statistics collection
18    pub enable_stats: bool,
19    /// Enable debug mode with verbose logging
20    pub debug_mode: bool,
21}
22
23impl Default for EngineConfig {
24    fn default() -> Self {
25        Self {
26            max_cycles: 100,
27            timeout: Some(Duration::from_secs(30)),
28            enable_stats: true,
29            debug_mode: false,
30        }
31    }
32}
33
34/// Result of rule engine execution
35#[derive(Debug, Clone)]
36pub struct GruleExecutionResult {
37    /// Number of execution cycles
38    pub cycle_count: usize,
39    /// Number of rules evaluated
40    pub rules_evaluated: usize,
41    /// Number of rules that fired
42    pub rules_fired: usize,
43    /// Total execution time
44    pub execution_time: Duration,
45}
46
47/// Rust Rule Engine - High-performance rule execution engine
48pub struct RustRuleEngine {
49    knowledge_base: KnowledgeBase,
50    config: EngineConfig,
51    custom_functions: HashMap<String, CustomFunction>,
52}
53
54impl RustRuleEngine {
55    /// Create a new RustRuleEngine with default configuration
56    pub fn new(knowledge_base: KnowledgeBase) -> Self {
57        Self {
58            knowledge_base,
59            config: EngineConfig::default(),
60            custom_functions: HashMap::new(),
61        }
62    }
63
64    /// Create a new RustRuleEngine with custom configuration
65    pub fn with_config(knowledge_base: KnowledgeBase, config: EngineConfig) -> Self {
66        Self {
67            knowledge_base,
68            config,
69            custom_functions: HashMap::new(),
70        }
71    }
72
73    /// Register a custom function
74    pub fn register_function<F>(&mut self, name: &str, func: F)
75    where
76        F: Fn(&[Value], &Facts) -> Result<Value> + Send + Sync + 'static,
77    {
78        self.custom_functions
79            .insert(name.to_string(), Box::new(func));
80    }
81
82    /// Check if a custom function is registered
83    pub fn has_function(&self, name: &str) -> bool {
84        self.custom_functions.contains_key(name)
85    }
86
87    /// Execute all rules in the knowledge base against the given facts
88    pub fn execute(&self, facts: &Facts) -> Result<GruleExecutionResult> {
89        let start_time = Instant::now();
90        let mut cycle_count = 0;
91        let mut rules_evaluated = 0;
92        let mut rules_fired = 0;
93
94        if self.config.debug_mode {
95            println!(
96                "🚀 Starting rule execution with {} rules",
97                self.knowledge_base.get_rules().len()
98            );
99        }
100
101        for cycle in 0..self.config.max_cycles {
102            cycle_count = cycle + 1;
103            let mut any_rule_fired = false;
104
105            // Check for timeout
106            if let Some(timeout) = self.config.timeout {
107                if start_time.elapsed() > timeout {
108                    return Err(RuleEngineError::EvaluationError {
109                        message: "Execution timeout exceeded".to_string(),
110                    });
111                }
112            }
113
114            // Get rules sorted by salience (highest first)
115            let mut rules = self.knowledge_base.get_rules().clone();
116            rules.sort_by(|a, b| b.salience.cmp(&a.salience));
117
118            for rule in &rules {
119                if !rule.enabled {
120                    continue;
121                }
122
123                rules_evaluated += 1;
124
125                if self.config.debug_mode {
126                    println!("📝 Evaluating rule: {}", rule.name);
127                }
128
129                // Evaluate rule conditions
130                if self.evaluate_conditions(&rule.conditions, facts)? {
131                    if self.config.debug_mode {
132                        println!(
133                            "🔥 Rule '{}' fired (salience: {})",
134                            rule.name, rule.salience
135                        );
136                    }
137
138                    // Execute actions
139                    for action in &rule.actions {
140                        self.execute_action(action, facts)?;
141                    }
142
143                    rules_fired += 1;
144                    any_rule_fired = true;
145                }
146            }
147
148            // If no rules fired in this cycle, we're done
149            if !any_rule_fired {
150                break;
151            }
152        }
153
154        let execution_time = start_time.elapsed();
155
156        Ok(GruleExecutionResult {
157            cycle_count,
158            rules_evaluated,
159            rules_fired,
160            execution_time,
161        })
162    }
163
164    /// Evaluate conditions against facts
165    fn evaluate_conditions(
166        &self,
167        conditions: &crate::engine::rule::ConditionGroup,
168        facts: &Facts,
169    ) -> Result<bool> {
170        use crate::engine::rule::ConditionGroup;
171
172        match conditions {
173            ConditionGroup::Single(condition) => self.evaluate_single_condition(condition, facts),
174            ConditionGroup::Compound {
175                left,
176                operator,
177                right,
178            } => {
179                let left_result = self.evaluate_conditions(left, facts)?;
180                let right_result = self.evaluate_conditions(right, facts)?;
181
182                match operator {
183                    crate::types::LogicalOperator::And => Ok(left_result && right_result),
184                    crate::types::LogicalOperator::Or => Ok(left_result || right_result),
185                    crate::types::LogicalOperator::Not => Err(RuleEngineError::EvaluationError {
186                        message: "NOT operator should not appear in compound conditions"
187                            .to_string(),
188                    }),
189                }
190            }
191            ConditionGroup::Not(condition) => {
192                let result = self.evaluate_conditions(condition, facts)?;
193                Ok(!result)
194            }
195        }
196    }
197
198    /// Evaluate a single condition
199    fn evaluate_single_condition(
200        &self,
201        condition: &crate::engine::rule::Condition,
202        facts: &Facts,
203    ) -> Result<bool> {
204        // Get the field value from facts
205        let field_value = facts.get_nested(&condition.field);
206
207        if field_value.is_none() {
208            return Ok(false); // Field not found, condition fails
209        }
210
211        let field_value = field_value.unwrap();
212
213        // Compare using the operator
214        Ok(condition.operator.evaluate(&field_value, &condition.value))
215    }
216
217    /// Execute an action
218    fn execute_action(&self, action: &ActionType, facts: &Facts) -> Result<()> {
219        match action {
220            ActionType::Set { field, value } => {
221                facts.set_nested(field, value.clone())?;
222                if self.config.debug_mode {
223                    println!("  ✅ Set {field} = {value:?}");
224                }
225            }
226            ActionType::Log { message } => {
227                println!("📋 LOG: {}", message);
228            }
229            ActionType::Call { function, args } => {
230                let result = self.execute_function_call(function, args, facts)?;
231                if self.config.debug_mode {
232                    println!("  📞 Called {function}({args:?}) -> {result}");
233                }
234            }
235            ActionType::MethodCall {
236                object,
237                method,
238                args,
239            } => {
240                let result = self.execute_method_call(object, method, args, facts)?;
241                if self.config.debug_mode {
242                    println!("  🔧 Called {object}.{method}({args:?}) -> {result}");
243                }
244            }
245            ActionType::Update { object } => {
246                if self.config.debug_mode {
247                    println!("  🔄 Updated {object}");
248                }
249                // Update action is mainly for working memory management
250                // In this implementation, it's mostly a no-op since we update in place
251            }
252            ActionType::Custom {
253                action_type,
254                params,
255            } => {
256                if self.config.debug_mode {
257                    println!("  🎯 Custom action: {action_type} with params: {params:?}");
258                }
259            }
260        }
261        Ok(())
262    }
263
264    /// Execute function call
265    fn execute_function_call(
266        &self,
267        function: &str,
268        args: &[Value],
269        facts: &Facts,
270    ) -> Result<String> {
271        let function_lower = function.to_lowercase();
272
273        // Handle built-in utility functions
274        match function_lower.as_str() {
275            "log" | "print" | "println" => self.handle_log_function(args),
276            "update" | "refresh" => self.handle_update_function(args),
277            "now" | "timestamp" => self.handle_timestamp_function(),
278            "random" => self.handle_random_function(args),
279            "format" | "sprintf" => self.handle_format_function(args),
280            "length" | "size" | "count" => self.handle_length_function(args),
281            "sum" | "add" => self.handle_sum_function(args),
282            "max" | "maximum" => self.handle_max_function(args),
283            "min" | "minimum" => self.handle_min_function(args),
284            "avg" | "average" => self.handle_average_function(args),
285            "round" => self.handle_round_function(args),
286            "floor" => self.handle_floor_function(args),
287            "ceil" | "ceiling" => self.handle_ceil_function(args),
288            "abs" | "absolute" => self.handle_abs_function(args),
289            "contains" | "includes" => self.handle_contains_function(args),
290            "startswith" | "begins_with" => self.handle_starts_with_function(args),
291            "endswith" | "ends_with" => self.handle_ends_with_function(args),
292            "lowercase" | "tolower" => self.handle_lowercase_function(args),
293            "uppercase" | "toupper" => self.handle_uppercase_function(args),
294            "trim" | "strip" => self.handle_trim_function(args),
295            "split" => self.handle_split_function(args),
296            "join" => self.handle_join_function(args),
297            _ => {
298                // Try to call custom user-defined function
299                self.handle_custom_function(function, args, facts)
300            }
301        }
302    }
303
304    /// Handle logging functions (log, print, println)
305    fn handle_log_function(&self, args: &[Value]) -> Result<String> {
306        let message = if args.is_empty() {
307            "".to_string()
308        } else if args.len() == 1 {
309            args[0].to_string()
310        } else {
311            args.iter()
312                .map(|v| v.to_string())
313                .collect::<Vec<_>>()
314                .join(" ")
315        };
316
317        println!("📋 {}", message);
318        Ok(message)
319    }
320
321    /// Handle update/refresh functions
322    fn handle_update_function(&self, args: &[Value]) -> Result<String> {
323        if let Some(arg) = args.first() {
324            Ok(format!("Updated: {}", arg.to_string()))
325        } else {
326            Ok("Updated".to_string())
327        }
328    }
329
330    /// Handle timestamp function
331    fn handle_timestamp_function(&self) -> Result<String> {
332        use std::time::{SystemTime, UNIX_EPOCH};
333        let timestamp = SystemTime::now()
334            .duration_since(UNIX_EPOCH)
335            .map_err(|e| RuleEngineError::EvaluationError {
336                message: format!("Failed to get timestamp: {}", e),
337            })?
338            .as_secs();
339        Ok(timestamp.to_string())
340    }
341
342    /// Handle random function
343    fn handle_random_function(&self, args: &[Value]) -> Result<String> {
344        use std::collections::hash_map::DefaultHasher;
345        use std::hash::{Hash, Hasher};
346
347        // Simple pseudo-random based on current time (for deterministic behavior in tests)
348        let mut hasher = DefaultHasher::new();
349        std::time::SystemTime::now().hash(&mut hasher);
350        let random_value = hasher.finish();
351
352        if args.is_empty() {
353            Ok((random_value % 100).to_string()) // 0-99
354        } else if let Some(Value::Number(max)) = args.first() {
355            let max_val = *max as u64;
356            Ok((random_value % max_val).to_string())
357        } else {
358            Ok(random_value.to_string())
359        }
360    }
361
362    /// Handle format function (simple sprintf-like)
363    fn handle_format_function(&self, args: &[Value]) -> Result<String> {
364        if args.is_empty() {
365            return Ok("".to_string());
366        }
367
368        let template = args[0].to_string();
369        let values: Vec<String> = args[1..].iter().map(|v| v.to_string()).collect();
370
371        // Simple placeholder replacement: {0}, {1}, etc.
372        let mut result = template;
373        for (i, value) in values.iter().enumerate() {
374            result = result.replace(&format!("{{{}}}", i), value);
375        }
376
377        Ok(result)
378    }
379
380    /// Handle length/size functions
381    fn handle_length_function(&self, args: &[Value]) -> Result<String> {
382        if let Some(arg) = args.first() {
383            match arg {
384                Value::String(s) => Ok(s.len().to_string()),
385                Value::Array(arr) => Ok(arr.len().to_string()),
386                Value::Object(obj) => Ok(obj.len().to_string()),
387                _ => Ok("1".to_string()), // Single value has length 1
388            }
389        } else {
390            Ok("0".to_string())
391        }
392    }
393
394    /// Handle sum function
395    fn handle_sum_function(&self, args: &[Value]) -> Result<String> {
396        let sum = args.iter().fold(0.0, |acc, val| match val {
397            Value::Number(n) => acc + n,
398            Value::Integer(i) => acc + (*i as f64),
399            _ => acc,
400        });
401        Ok(sum.to_string())
402    }
403
404    /// Handle max function
405    fn handle_max_function(&self, args: &[Value]) -> Result<String> {
406        let max = args.iter().fold(f64::NEG_INFINITY, |acc, val| match val {
407            Value::Number(n) => acc.max(*n),
408            Value::Integer(i) => acc.max(*i as f64),
409            _ => acc,
410        });
411        Ok(max.to_string())
412    }
413
414    /// Handle min function
415    fn handle_min_function(&self, args: &[Value]) -> Result<String> {
416        let min = args.iter().fold(f64::INFINITY, |acc, val| match val {
417            Value::Number(n) => acc.min(*n),
418            Value::Integer(i) => acc.min(*i as f64),
419            _ => acc,
420        });
421        Ok(min.to_string())
422    }
423
424    /// Handle average function
425    fn handle_average_function(&self, args: &[Value]) -> Result<String> {
426        if args.is_empty() {
427            return Ok("0".to_string());
428        }
429
430        let (sum, count) = args.iter().fold((0.0, 0), |(sum, count), val| match val {
431            Value::Number(n) => (sum + n, count + 1),
432            Value::Integer(i) => (sum + (*i as f64), count + 1),
433            _ => (sum, count),
434        });
435
436        if count > 0 {
437            Ok((sum / count as f64).to_string())
438        } else {
439            Ok("0".to_string())
440        }
441    }
442
443    /// Handle mathematical functions
444    fn handle_round_function(&self, args: &[Value]) -> Result<String> {
445        if let Some(Value::Number(n)) = args.first() {
446            Ok(n.round().to_string())
447        } else if let Some(Value::Integer(i)) = args.first() {
448            Ok(i.to_string())
449        } else {
450            Err(RuleEngineError::EvaluationError {
451                message: "round() requires a numeric argument".to_string(),
452            })
453        }
454    }
455
456    fn handle_floor_function(&self, args: &[Value]) -> Result<String> {
457        if let Some(Value::Number(n)) = args.first() {
458            Ok(n.floor().to_string())
459        } else if let Some(Value::Integer(i)) = args.first() {
460            Ok(i.to_string())
461        } else {
462            Err(RuleEngineError::EvaluationError {
463                message: "floor() requires a numeric argument".to_string(),
464            })
465        }
466    }
467
468    fn handle_ceil_function(&self, args: &[Value]) -> Result<String> {
469        if let Some(Value::Number(n)) = args.first() {
470            Ok(n.ceil().to_string())
471        } else if let Some(Value::Integer(i)) = args.first() {
472            Ok(i.to_string())
473        } else {
474            Err(RuleEngineError::EvaluationError {
475                message: "ceil() requires a numeric argument".to_string(),
476            })
477        }
478    }
479
480    fn handle_abs_function(&self, args: &[Value]) -> Result<String> {
481        if let Some(Value::Number(n)) = args.first() {
482            Ok(n.abs().to_string())
483        } else if let Some(Value::Integer(i)) = args.first() {
484            Ok(i.abs().to_string())
485        } else {
486            Err(RuleEngineError::EvaluationError {
487                message: "abs() requires a numeric argument".to_string(),
488            })
489        }
490    }
491
492    /// Handle string functions
493    fn handle_contains_function(&self, args: &[Value]) -> Result<String> {
494        if args.len() >= 2 {
495            let haystack = args[0].to_string();
496            let needle = args[1].to_string();
497            Ok(haystack.contains(&needle).to_string())
498        } else {
499            Err(RuleEngineError::EvaluationError {
500                message: "contains() requires 2 arguments".to_string(),
501            })
502        }
503    }
504
505    fn handle_starts_with_function(&self, args: &[Value]) -> Result<String> {
506        if args.len() >= 2 {
507            let text = args[0].to_string();
508            let prefix = args[1].to_string();
509            Ok(text.starts_with(&prefix).to_string())
510        } else {
511            Err(RuleEngineError::EvaluationError {
512                message: "startswith() requires 2 arguments".to_string(),
513            })
514        }
515    }
516
517    fn handle_ends_with_function(&self, args: &[Value]) -> Result<String> {
518        if args.len() >= 2 {
519            let text = args[0].to_string();
520            let suffix = args[1].to_string();
521            Ok(text.ends_with(&suffix).to_string())
522        } else {
523            Err(RuleEngineError::EvaluationError {
524                message: "endswith() requires 2 arguments".to_string(),
525            })
526        }
527    }
528
529    fn handle_lowercase_function(&self, args: &[Value]) -> Result<String> {
530        if let Some(arg) = args.first() {
531            Ok(arg.to_string().to_lowercase())
532        } else {
533            Err(RuleEngineError::EvaluationError {
534                message: "lowercase() requires 1 argument".to_string(),
535            })
536        }
537    }
538
539    fn handle_uppercase_function(&self, args: &[Value]) -> Result<String> {
540        if let Some(arg) = args.first() {
541            Ok(arg.to_string().to_uppercase())
542        } else {
543            Err(RuleEngineError::EvaluationError {
544                message: "uppercase() requires 1 argument".to_string(),
545            })
546        }
547    }
548
549    fn handle_trim_function(&self, args: &[Value]) -> Result<String> {
550        if let Some(arg) = args.first() {
551            Ok(arg.to_string().trim().to_string())
552        } else {
553            Err(RuleEngineError::EvaluationError {
554                message: "trim() requires 1 argument".to_string(),
555            })
556        }
557    }
558
559    fn handle_split_function(&self, args: &[Value]) -> Result<String> {
560        if args.len() >= 2 {
561            let text = args[0].to_string();
562            let delimiter = args[1].to_string();
563            let parts: Vec<String> = text.split(&delimiter).map(|s| s.to_string()).collect();
564            Ok(format!("{:?}", parts)) // Return as debug string for now
565        } else {
566            Err(RuleEngineError::EvaluationError {
567                message: "split() requires 2 arguments".to_string(),
568            })
569        }
570    }
571
572    fn handle_join_function(&self, args: &[Value]) -> Result<String> {
573        if args.len() >= 2 {
574            let delimiter = args[0].to_string();
575            let parts: Vec<String> = args[1..].iter().map(|v| v.to_string()).collect();
576            Ok(parts.join(&delimiter))
577        } else {
578            Err(RuleEngineError::EvaluationError {
579                message: "join() requires at least 2 arguments".to_string(),
580            })
581        }
582    }
583
584    /// Handle custom user-defined functions
585    fn handle_custom_function(
586        &self,
587        function: &str,
588        args: &[Value],
589        facts: &Facts,
590    ) -> Result<String> {
591        // Check if we have a registered custom function
592        if let Some(custom_func) = self.custom_functions.get(function) {
593            if self.config.debug_mode {
594                println!("🎯 Calling registered function: {}({:?})", function, args);
595            }
596
597            match custom_func(args, facts) {
598                Ok(result) => Ok(result.to_string()),
599                Err(e) => Err(e),
600            }
601        } else {
602            // Function not found - return error or placeholder
603            if self.config.debug_mode {
604                println!("⚠️ Custom function '{}' not registered", function);
605            }
606
607            Err(RuleEngineError::EvaluationError {
608                message: format!("Function '{}' is not registered. Use engine.register_function() to add custom functions.", function),
609            })
610        }
611    }
612
613    /// Execute method call on object
614    fn execute_method_call(
615        &self,
616        object_name: &str,
617        method: &str,
618        args: &[Value],
619        facts: &Facts,
620    ) -> Result<String> {
621        // Get the object from facts
622        let Some(object_value) = facts.get(object_name) else {
623            return Err(RuleEngineError::EvaluationError {
624                message: format!("Object '{}' not found in facts", object_name),
625            });
626        };
627
628        let method_lower = method.to_lowercase();
629
630        // Handle setter methods (set + property name)
631        if method_lower.starts_with("set") && args.len() == 1 {
632            return self.handle_setter_method(object_name, method, &args[0], object_value, facts);
633        }
634
635        // Handle getter methods (get + property name)
636        if method_lower.starts_with("get") && args.is_empty() {
637            return self.handle_getter_method(object_name, method, &object_value);
638        }
639
640        // Handle built-in methods
641        match method_lower.as_str() {
642            "tostring" => Ok(object_value.to_string()),
643            "update" => {
644                facts.add_value(object_name, object_value)?;
645                Ok(format!("Updated {}", object_name))
646            }
647            "reset" => self.handle_reset_method(object_name, object_value, facts),
648            _ => self.handle_property_access_or_fallback(
649                object_name,
650                method,
651                args.len(),
652                &object_value,
653            ),
654        }
655    }
656
657    /// Handle setter method calls (setXxx)
658    fn handle_setter_method(
659        &self,
660        object_name: &str,
661        method: &str,
662        new_value: &Value,
663        mut object_value: Value,
664        facts: &Facts,
665    ) -> Result<String> {
666        let property_name = Self::extract_property_name_from_setter(method);
667
668        match object_value {
669            Value::Object(ref mut obj) => {
670                obj.insert(property_name.clone(), new_value.clone());
671                facts.add_value(object_name, object_value)?;
672                Ok(format!(
673                    "Set {} to {}",
674                    property_name,
675                    new_value.to_string()
676                ))
677            }
678            _ => Err(RuleEngineError::EvaluationError {
679                message: format!("Cannot call setter on non-object type: {}", object_name),
680            }),
681        }
682    }
683
684    /// Handle getter method calls (getXxx)
685    fn handle_getter_method(
686        &self,
687        object_name: &str,
688        method: &str,
689        object_value: &Value,
690    ) -> Result<String> {
691        let property_name = Self::extract_property_name_from_getter(method);
692
693        match object_value {
694            Value::Object(obj) => {
695                if let Some(value) = obj.get(&property_name) {
696                    Ok(value.to_string())
697                } else {
698                    Err(RuleEngineError::EvaluationError {
699                        message: format!(
700                            "Property '{}' not found on object '{}'",
701                            property_name, object_name
702                        ),
703                    })
704                }
705            }
706            _ => Err(RuleEngineError::EvaluationError {
707                message: format!("Cannot call getter on non-object type: {}", object_name),
708            }),
709        }
710    }
711
712    /// Handle reset method call
713    fn handle_reset_method(
714        &self,
715        object_name: &str,
716        mut object_value: Value,
717        facts: &Facts,
718    ) -> Result<String> {
719        match object_value {
720            Value::Object(ref mut obj) => {
721                obj.clear();
722                facts.add_value(object_name, object_value)?;
723                Ok(format!("Reset {}", object_name))
724            }
725            _ => Err(RuleEngineError::EvaluationError {
726                message: format!("Cannot reset non-object type: {}", object_name),
727            }),
728        }
729    }
730
731    /// Handle property access or fallback to generic method call
732    fn handle_property_access_or_fallback(
733        &self,
734        object_name: &str,
735        method: &str,
736        arg_count: usize,
737        object_value: &Value,
738    ) -> Result<String> {
739        if let Value::Object(obj) = object_value {
740            // Try exact property name match
741            if let Some(value) = obj.get(method) {
742                return Ok(value.to_string());
743            }
744
745            // Try capitalized property name
746            let capitalized_method = Self::capitalize_first_letter(method);
747            if let Some(value) = obj.get(&capitalized_method) {
748                return Ok(value.to_string());
749            }
750        }
751
752        // Fallback to generic response
753        Ok(format!(
754            "Called {}.{} with {} args",
755            object_name, method, arg_count
756        ))
757    }
758
759    /// Extract property name from setter method (setXxx -> Xxx)
760    fn extract_property_name_from_setter(method: &str) -> String {
761        let property_name = &method[3..]; // Remove "set" prefix
762        Self::capitalize_first_letter(property_name)
763    }
764
765    /// Extract property name from getter method (getXxx -> Xxx)
766    fn extract_property_name_from_getter(method: &str) -> String {
767        let property_name = &method[3..]; // Remove "get" prefix
768        Self::capitalize_first_letter(property_name)
769    }
770
771    /// Helper function to capitalize first letter of a string
772    fn capitalize_first_letter(s: &str) -> String {
773        if s.is_empty() {
774            return String::new();
775        }
776        let mut chars = s.chars();
777        match chars.next() {
778            None => String::new(),
779            Some(first) => first.to_uppercase().collect::<String>() + chars.as_str(),
780        }
781    }
782}