Skip to main content

ferrous_opencc/
lib.rs

1//! # Pure Rust implementation of `OpenCC`
2//!
3//! Provides high-performance conversion between Traditional Chinese and Simplified Chinese.
4//!
5//! ## Examples
6//!
7//! ```
8//! use ferrous_opencc::OpenCC;
9//!
10//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
11//! // Create OpenCC instance
12//! let opencc = OpenCC::from_config(ferrous_opencc::config::BuiltinConfig::S2t)?;
13//!
14//! // Convert text
15//! let text = "开放中文转换是完全由 Rust 实现的。";
16//! let converted = opencc.convert(text);
17//!
18//! assert_eq!(converted, "開放中文轉換是完全由 Rust 實現的。");
19//! # Ok(())
20//! # }
21//! ```
22
23pub mod config;
24mod conversion;
25pub mod dictionary;
26pub mod error;
27#[cfg(not(target_arch = "wasm32"))]
28pub mod ffi;
29
30use std::path::Path;
31
32use config::Config;
33use conversion::ConversionChain;
34use error::Result;
35#[cfg(feature = "wasm")]
36use wasm_bindgen::prelude::*;
37
38use crate::{
39    config::BuiltinConfig,
40    dictionary::embedded,
41};
42
43/// The core `OpenCC` converter
44#[cfg_attr(feature = "wasm", wasm_bindgen)]
45pub struct OpenCC {
46    /// Configuration name
47    name: String,
48    /// The dictionary chain used for conversion
49    conversion_chain: ConversionChain,
50}
51
52impl OpenCC {
53    /// Creates a new `OpenCC` instance from a configuration file.
54    /// Parses the JSON configuration file, loads all required dictionaries, and builds the
55    /// conversion chain.
56    ///
57    /// # Arguments
58    ///
59    /// * `config_path`: Path to the main JSON configuration file (e.g., `s2t.json`)
60    ///
61    /// # Returns
62    ///
63    /// A `Result` containing the new `OpenCC` instance, or an error if loading fails
64    pub fn new<P: AsRef<Path>>(config_path: P) -> Result<Self> {
65        let config = Config::from_file(config_path)?;
66        let config_dir = config.get_config_directory();
67
68        let conversion_chain = ConversionChain::from_config(&config.conversion_chain, config_dir)?;
69
70        Ok(Self {
71            name: config.name,
72            conversion_chain,
73        })
74    }
75
76    /// Creates an `OpenCC` instance from a built-in configuration.
77    ///
78    /// # Example
79    /// ```
80    /// use ferrous_opencc::{
81    ///     OpenCC,
82    ///     config::BuiltinConfig,
83    ///     error::Result,
84    /// };
85    ///
86    /// fn main() -> Result<()> {
87    ///     let opencc = OpenCC::from_config(BuiltinConfig::S2t)?;
88    ///     Ok(())
89    /// }
90    /// ```
91    pub fn from_config(config_enum: BuiltinConfig) -> Result<Self> {
92        let name = config_enum.to_filename();
93        let config_str = embedded::EMBEDDED_CONFIGS
94            .get(name)
95            .ok_or_else(|| error::OpenCCError::ConfigNotFound(name.to_string()))?;
96
97        let config: Config = config_str.parse()?;
98
99        let conversion_chain = ConversionChain::from_config_embedded(&config.conversion_chain)?;
100
101        Ok(Self {
102            name: config.name,
103            conversion_chain,
104        })
105    }
106
107    /// Converts a string according to the loaded configuration.
108    ///
109    /// # Arguments
110    ///
111    /// * `input`: The string to convert
112    ///
113    /// # Returns
114    ///
115    /// The converted string
116    #[must_use]
117    pub fn convert(&self, input: &str) -> String {
118        self.conversion_chain.convert(input)
119    }
120
121    /// Returns the name of the currently loaded configuration
122    #[must_use]
123    pub fn name(&self) -> &str {
124        &self.name
125    }
126}
127
128#[cfg(feature = "wasm")]
129#[wasm_bindgen]
130impl OpenCC {
131    /// Creates a new `OpenCC` instance.
132    ///
133    /// @param {`string`} `config_name` - The name of the built-in configuration to use, e.g.,
134    /// "s2t.json". @returns {`OpenCC`} - An `OpenCC` instance.
135    /// @throws {`JsValue`} - Throws an error object if configuration loading fails.
136    ///
137    /// @example
138    /// ```javascript
139    /// import init, { OpenCC } from './pkg/ferrous_opencc.js';
140    ///
141    /// async function main() {
142    ///   await init();
143    ///   try {
144    ///     const converter = new OpenCC("s2t.json");
145    ///     console.log('Load success:', converter.name);
146    ///   } catch (err) {
147    ///     console.error('Load failed:', err);
148    ///   }
149    /// }
150    /// main();
151    /// ```
152    #[wasm_bindgen(constructor)]
153    pub fn new_wasm(config_name: &str) -> std::result::Result<Self, JsValue> {
154        let config_enum = BuiltinConfig::from_filename(config_name)
155            .map_err(|e| JsValue::from_str(&e.to_string()))?;
156        Self::from_config(config_enum).map_err(|e| JsValue::from_str(&e.to_string()))
157    }
158
159    /// Converts a string according to the loaded configuration.
160    ///
161    /// @param {string} input - The string to convert.
162    /// @returns {string} - The converted string.
163    ///
164    /// @example
165    /// ```javascript
166    /// const traditionalText = converter.convert("开放中文转换");
167    /// console.log(traditionalText); // Expected: 開放中文轉換
168    /// ```
169    #[wasm_bindgen(js_name = convert)]
170    #[must_use]
171    pub fn convert_wasm(&self, input: &str) -> String {
172        self.convert(input)
173    }
174
175    /// Gets the name of the currently loaded configuration.
176    ///
177    /// @returns {string} - The name of the configuration.
178    ///
179    /// @example
180    /// ```javascript
181    /// const configName = converter.name;
182    /// console.log(configName);
183    /// ```
184    #[wasm_bindgen(getter, js_name = name)]
185    #[must_use]
186    pub fn name_wasm(&self) -> String {
187        self.name.clone()
188    }
189}