subx_core/lib.rs
1//! SubX Core: Reusable Subtitle Processing Library
2//!
3//! `subx-core` is the library half of the SubX project: the configuration
4//! system, the processing engines, the shared error type and the external
5//! service integrations, packaged so they can be consumed without the
6//! command-line interface. It features AI-powered matching, format
7//! conversion, audio synchronization, and advanced encoding detection.
8//!
9//! It is licensed under GPL-3.0-or-later and is designed to be consumed by
10//! the `subx-cli` command-line tool, by graphical frontends such as the Tauri
11//! GUI at <https://github.com/jim60105/subx>, and by any Rust program that
12//! needs subtitle processing capabilities.
13//!
14//! # Repository Relationship
15//!
16//! In the `subx-cli` repository this crate is mounted as a git submodule at
17//! `subx-cli/subx-core/` and built as a Cargo workspace member. It is also a
18//! fully standalone crate: a plain `git clone` of this repository followed by
19//! `cargo build` works without any other repository present, which is the
20//! contract that keeps crates.io consumers and `docs.rs` builds working.
21//!
22//! This crate never references `subx-cli` — not in code, not in an intra-doc
23//! link, not in a doctest. The dependency only points the other way, so any
24//! such reference would be unresolvable rather than merely stale, and it is
25//! rejected by a boundary guard test in the `subx-cli` repository.
26//!
27//! # Modules
28//!
29//! - [`config`] - Configuration management and validation
30//! - [`core`] - Core processing engines (formats, matching, sync)
31//! - [`error`] - Comprehensive error handling system
32//! - [`services`] - External service integrations (AI, audio processing)
33//!
34//! # Module Path Stability (a deliberate decision, not an oversight)
35//!
36//! Engine paths keep the redundant `core::` segment: the canonical path of
37//! the match engine is [`core::matcher::MatchEngine`], written
38//! `subx_core::core::matcher::MatchEngine`. This stutters, and a flatter
39//! `subx_core::matcher::…` surface would read better in isolation. It is
40//! rejected deliberately: these items were reachable at exactly these
41//! relative paths under the `subx-cli` crate's name for the library's entire
42//! history, and downstream consumers — chiefly the Tauri GUI — reach roughly
43//! thirty of them by path. Preserving the tree makes their migration a pure
44//! crate-name substitution. Flattening or otherwise reshaping these paths is
45//! therefore a breaking change that requires a major version of this crate,
46//! and no module is re-exported at the crate root alongside its canonical
47//! path, because a second public path would make intra-doc links ambiguous
48//! under `broken_intra_doc_links = "deny"`.
49//!
50//! # Features
51//!
52//! - `archive-rar` - enable RAR archive extraction (optional `unrar`
53//! dependency; without it the archive layer exposes a disabled-feature
54//! stub)
55//! - `slow-tests` - compile long-running format round-trip tests
56//!
57//! # Examples
58//!
59//! Configuration access through the injected service:
60//!
61//! ```rust,no_run
62//! use subx_core::config::{ConfigService, TestConfigService};
63//!
64//! // Create a configuration service
65//! let config_service = TestConfigService::with_defaults();
66//! let config = config_service.config();
67//!
68//! // Use the configuration for processing...
69//! ```
70//!
71//! All operations return a [`Result<T>`] type that wraps [`error::SubXError`]:
72//!
73//! ```rust
74//! use subx_core::{error::SubXError, Result};
75//!
76//! fn example_operation() -> Result<String> {
77//! // This could fail with various error types
78//! Err(SubXError::config("Missing configuration"))
79//! }
80//! ```
81//!
82//! Dependency-injected configuration with AI settings:
83//!
84//! ```rust,no_run
85//! use subx_core::config::{Config, TestConfigService};
86//!
87//! // Create configuration service with AI settings
88//! let config_service = TestConfigService::with_ai_settings("openai", "gpt-4.1");
89//! let config = config_service.config();
90//!
91//! // Access configuration values
92//! println!("AI Provider: {}", config.ai.provider);
93//! println!("AI Model: {}", config.ai.model);
94//! ```
95
96#![allow(
97 clippy::new_without_default,
98 clippy::manual_clamp,
99 clippy::useless_vec,
100 clippy::items_after_test_module,
101 clippy::needless_borrow,
102 clippy::uninlined_format_args,
103 clippy::collapsible_if
104)]
105#![warn(missing_docs)]
106#![warn(rustdoc::missing_crate_level_docs)]
107
108pub mod config;
109pub mod core;
110pub mod error;
111pub mod services;
112
113/// Shared test fixtures for the SubX integration suites.
114///
115/// Compiled only with the `test-support` feature, which no shipping build
116/// activates — `subx-cli` turns it on through a `[dev-dependencies]`
117/// declaration of this crate, and this crate's own integration tests reach
118/// it through a path-only self dev-dependency, so neither mechanism can
119/// leak into a release artifact. The missing-documentation lint is relaxed
120/// on this declaration because the module's items are test scaffolding
121/// documented by their surrounding prose rather than rustdoc; the
122/// `broken_intra_doc_links = "deny"` lint still applies inside it.
123#[cfg(feature = "test-support")]
124#[allow(missing_docs)]
125pub mod test_support;
126
127pub use config::Config;
128// Re-export the configuration service system at the crate root.
129pub use config::{
130 ConfigService, EnvironmentProvider, ProductionConfigService, SystemEnvironmentProvider,
131 TestConfigBuilder, TestConfigService, TestEnvironmentProvider,
132};
133
134/// Convenient type alias for `Result<T, SubXError>`.
135///
136/// This type alias simplifies error handling throughout the SubX library
137/// by providing a default error type for all fallible operations.
138pub type Result<T> = error::SubXResult<T>;
139
140/// Library version string.
141///
142/// This constant provides the current version of the `subx-core` library,
143/// automatically populated from `Cargo.toml` at compile time. It reports
144/// this crate's own version and is independent of the version of any
145/// consumer such as `subx-cli`.
146///
147/// # Examples
148///
149/// ```rust
150/// use subx_core::VERSION;
151///
152/// // The version is always present and follows semver.
153/// assert!(!VERSION.is_empty());
154/// assert!(VERSION.split('.').next().is_some());
155/// ```
156pub const VERSION: &str = env!("CARGO_PKG_VERSION");
157
158#[cfg(test)]
159mod tests {
160 use super::VERSION;
161
162 #[test]
163 fn version_is_not_empty() {
164 assert!(!VERSION.is_empty());
165 }
166
167 #[test]
168 fn version_matches_cargo_pkg_version() {
169 assert_eq!(VERSION, env!("CARGO_PKG_VERSION"));
170 }
171}