formatorbit_core/
lib.rs

1//! Formatorbit Core
2//!
3//! A cross-platform data format converter. Input data (e.g., `691E01B8`) and
4//! get all possible interpretations and conversions automatically.
5
6pub mod convert;
7pub mod format;
8pub mod formats;
9pub mod types;
10
11pub use format::{Format, FormatInfo};
12pub use types::*;
13
14use formats::{
15    Base64Format, BytesToIntFormat, ColorFormat, DateTimeFormat, DecimalFormat, HexFormat,
16    IpAddrFormat, JsonFormat, MsgPackFormat, UrlEncodingFormat, Utf8Format, UuidFormat,
17};
18
19/// Main entry point - a configured converter instance.
20pub struct Formatorbit {
21    formats: Vec<Box<dyn Format>>,
22}
23
24impl Formatorbit {
25    /// Create with only built-in formats.
26    #[must_use]
27    pub fn new() -> Self {
28        Self {
29            formats: vec![
30                // High-specificity formats first
31                Box::new(UuidFormat),
32                Box::new(IpAddrFormat),
33                Box::new(ColorFormat),
34                Box::new(UrlEncodingFormat),
35                // Common formats
36                Box::new(HexFormat),
37                Box::new(Base64Format),
38                Box::new(DecimalFormat),
39                Box::new(DateTimeFormat),
40                Box::new(JsonFormat),
41                Box::new(Utf8Format),
42                // Conversion-only formats (don't parse strings directly)
43                Box::new(BytesToIntFormat),
44                Box::new(MsgPackFormat),
45            ],
46        }
47    }
48
49    /// Parse input and return all possible interpretations.
50    pub fn interpret(&self, input: &str) -> Vec<Interpretation> {
51        let mut results = Vec::new();
52        for format in &self.formats {
53            results.extend(format.parse(input));
54        }
55        // Sort by confidence, highest first
56        results.sort_by(|a, b| b.confidence.partial_cmp(&a.confidence).unwrap());
57        results
58    }
59
60    /// Find all possible conversions from a value.
61    pub fn convert(&self, value: &CoreValue) -> Vec<Conversion> {
62        convert::find_all_conversions(&self.formats, value)
63    }
64
65    /// Combined: interpret input and find all conversions.
66    pub fn convert_all(&self, input: &str) -> Vec<ConversionResult> {
67        self.interpret(input)
68            .into_iter()
69            .map(|interp| {
70                let conversions = self.convert(&interp.value);
71                ConversionResult {
72                    input: input.to_string(),
73                    interpretation: interp,
74                    conversions,
75                }
76            })
77            .collect()
78    }
79
80    /// Get info about all registered formats (for help/documentation).
81    pub fn format_infos(&self) -> Vec<FormatInfo> {
82        self.formats.iter().map(|f| f.info()).collect()
83    }
84
85    /// Parse input with only the specified formats (by id or alias).
86    /// If `format_filter` is empty, all formats are used.
87    pub fn interpret_filtered(&self, input: &str, format_filter: &[String]) -> Vec<Interpretation> {
88        if format_filter.is_empty() {
89            return self.interpret(input);
90        }
91
92        let mut results = Vec::new();
93        for format in &self.formats {
94            // Check if this format matches any of the filter names
95            let matches = format_filter.iter().any(|name| format.matches_name(name));
96            if matches {
97                results.extend(format.parse(input));
98            }
99        }
100        // Sort by confidence, highest first
101        results.sort_by(|a, b| b.confidence.partial_cmp(&a.confidence).unwrap());
102        results
103    }
104
105    /// Combined: interpret input (with filter) and find all conversions.
106    pub fn convert_all_filtered(
107        &self,
108        input: &str,
109        format_filter: &[String],
110    ) -> Vec<ConversionResult> {
111        self.interpret_filtered(input, format_filter)
112            .into_iter()
113            .map(|interp| {
114                let conversions = self.convert(&interp.value);
115                ConversionResult {
116                    input: input.to_string(),
117                    interpretation: interp,
118                    conversions,
119                }
120            })
121            .collect()
122    }
123}
124
125impl Default for Formatorbit {
126    fn default() -> Self {
127        Self::new()
128    }
129}