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}