dmsc/c/core.rs
1//! Copyright © 2025-2026 Wenze Wei. All Rights Reserved.
2//!
3//! This file is part of DMSC.
4//! The DMSC project belongs to the Dunimd Team.
5//!
6//! Licensed under the Apache License, Version 2.0 (the "License");
7//! You may not use this file except in compliance with the License.
8//! You may obtain a copy of the License at
9//!
10//! http://www.apache.org/licenses/LICENSE-2.0
11//!
12//! Unless required by applicable law or agreed to in writing, software
13//! distributed under the License is distributed on an "AS IS" BASIS,
14//! WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15//! See the License for the specific language governing permissions and
16//! limitations under the License.
17
18//! # Core Module C API
19//!
20//! This module provides C language bindings for DMSC's core application infrastructure.
21//! The core module serves as the foundation for building DMSC applications, providing
22//! application lifecycle management, configuration handling, and initialization routines.
23//! This C API enables C/C++ applications to leverage DMSC's powerful application builder
24//! and configuration management capabilities.
25//!
26//! ## Module Architecture
27//!
28//! The core module comprises two essential components that form the backbone of any
29//! DMSC application:
30//!
31//! - **DMSCAppBuilder**: Fluent builder pattern implementation for constructing DMSC
32//! applications with type-safe configuration. The builder supports registration of
33//! modules, services, and middleware components through a declarative API. It handles
34//! dependency injection, service discovery, and lifecycle coordination across all
35//! registered components. The builder produces a fully initialized DMSCApp instance
36//! ready for execution.
37//!
38//! - **DMSCConfig**: Unified configuration management interface supporting multiple
39//! configuration sources including environment variables, command-line arguments,
40//! configuration files (YAML, TOML, JSON), and remote configuration services.
41//! The configuration system provides type-safe value retrieval with automatic
42//! type conversion, validation, and hot-reload capabilities for dynamic
43//! configuration updates in running applications.
44//!
45//! ## Application Lifecycle
46//!
47//! DMSC applications follow a well-defined lifecycle:
48//!
49//! 1. **Initialization Phase**: Application builder creates and configures components.
50//! Services are registered, dependencies are wired, and configuration is loaded.
51//!
52//! 2. **Startup Phase**: All registered services and modules are initialized in
53//! dependency order. Health checks verify component readiness.
54//!
55//! 3. **Running Phase**: Application enters active state, processing requests or
56//! executing scheduled tasks. Components operate according to their configured
57//! behavior.
58//!
59//! 4. **Shutdown Phase**: Graceful shutdown initiates component cleanup in reverse
60//! dependency order. Resources are released, connections are closed, and state
61//! is persisted as needed.
62//!
63//! ## Configuration System
64//!
65//! The configuration module implements a hierarchical configuration model:
66//!
67//! - **Sources**: Environment variables override file-based settings, which override
68//! default values. Multiple sources can coexist with configurable precedence.
69//!
70//! - **Formats**: Native support for YAML, TOML, JSON configuration files. Each
71//! format has optimized parsing and schema validation.
72//!
73//! - **Validation**: Configuration values undergo validation against defined schemas.
74//! Type mismatches, missing required fields, and constraint violations are detected.
75//!
76//! - **Hot Reload**: Configuration files are monitored for changes. Updates are
77//! applied atomically without application restart. Subscribers are notified of changes.
78//!
79//! ## Memory Management
80//!
81//! All C API objects use opaque pointers with manual memory management:
82//!
83//! - Constructor functions allocate new instances on the heap
84//! - Destructor functions must be called to release memory
85//! - Objects must not be used after being freed
86//! - Null pointer checks are required before all operations
87//!
88//! ## Thread Safety
89//!
90//! The underlying Rust implementations are thread-safe:
91//!
92//! - Application builder operations require external synchronization
93//! - Configuration reads are concurrent-safe after initialization
94//! - Configuration writes require exclusive access
95//!
96//! ## Usage Example
97//!
98//! ```c
99//! // Create application configuration
100//! CDMSCConfig* config = dmsc_config_new();
101//!
102//! // Load configuration from file
103//! int result = dmsc_config_load_file(config, "config.yaml");
104//!
105//! // Get configuration value
106//! char* value = dmsc_config_get_string(config, "database.url");
107//!
108//! // Create application builder
109//! CDMSCAppBuilder* builder = dmsc_app_builder_new();
110//!
111//! // Configure builder with configuration
112//! dmsc_app_builder_configure(builder, config);
113//!
114//! // Build and run application
115//! dmsc_app_builder_build(builder);
116//!
117//! // Cleanup
118//! dmsc_app_builder_free(builder);
119//! dmsc_config_free(config);
120//! dmsc_string_free(value);
121//! ```
122//!
123//! ## Dependencies
124//!
125//! This module depends on the following DMSC components:
126//!
127//! - `crate::core`: Rust core module implementation
128//! - `crate::prelude`: Common types and traits
129//!
130//! ## Feature Flags
131//!
132//! The core module is always enabled as it provides fundamental infrastructure
133//! required by all other DMSC components.
134
135use crate::prelude::{DMSCAppBuilder, DMSCConfig};
136use std::ffi::{c_char, CString};
137
138/// Opaque C wrapper structure for DMSCAppBuilder.
139///
140/// Provides C-compatible interface to the Rust application builder implementation.
141/// The builder uses the fluent builder pattern to construct DMSC applications with
142/// proper dependency injection and lifecycle management.
143///
144/// # Builder Responsibilities
145///
146/// The application builder handles:
147///
148/// - Service registration and dependency management
149/// - Middleware composition and ordering
150/// - Configuration propagation to components
151/// - Lifecycle event registration
152/// - Application initialization and startup coordination
153///
154/// # Builder Pattern
155///
156/// The builder implements a fluent interface allowing method chaining:
157///
158/// ```c
159/// dmsc_app_builder_register_module(builder, module_a);
160/// dmsc_app_builder_register_module(builder, module_b);
161/// dmsc_app_builder_configure(builder, config);
162/// dmsc_app_builder_with_middleware(builder, middleware_1);
163/// dmsc_app_builder_with_middleware(builder, middleware_2);
164/// ```
165///
166/// # Thread Safety
167///
168/// The builder is not thread-safe. All builder operations should occur from a
169/// single thread before application startup. Concurrent builder access results
170/// in undefined behavior.
171#[repr(C)]
172pub struct CDMSCAppBuilder {
173 inner: DMSCAppBuilder,
174}
175
176/// Opaque C wrapper structure for DMSCConfig.
177///
178/// Provides C-compatible interface to the unified configuration management system.
179/// The configuration object provides type-safe access to configuration values
180/// from multiple sources with automatic type conversion and validation.
181///
182/// # Configuration Sources
183///
184/// The configuration system aggregates values from:
185///
186/// - Default values defined in code
187/// - Configuration files (YAML, TOML, JSON)
188/// - Environment variables
189/// - Command-line arguments
190/// - Remote configuration services (etcd, Consul)
191///
192/// # Value Resolution
193///
194/// Configuration values are resolved using precedence order:
195///
196/// 1. Environment variables (highest priority)
197/// 2. Command-line arguments
198/// 3. Remote configuration
199/// 4. Configuration files
200/// 5. Default values (lowest priority)
201///
202/// # Type Safety
203///
204/// The configuration system provides type-safe value retrieval:
205///
206/// - get_string(): Retrieve string values
207/// - get_int(): Retrieve integer values with automatic conversion
208/// - get_bool(): Retrieve boolean values
209/// - get_float(): Retrieve floating-point values
210/// - get_list(): Retrieve array values
211///
212/// Invalid type requests return default values or trigger validation errors.
213#[repr(C)]
214pub struct CDMSCConfig {
215 inner: DMSCConfig,
216}
217
218/// Creates a new CDMSCAppBuilder instance.
219///
220/// Initializes an empty application builder ready for component registration.
221/// The builder starts with default configuration and no registered modules.
222///
223/// # Returns
224///
225/// Pointer to newly allocated CDMSCAppBuilder on success. Never returns NULL
226/// as the implementation uses infallible construction. The returned pointer
227/// must be freed using dmsc_app_builder_free().
228///
229/// # Initial State
230///
231/// A newly created builder:
232///
233/// - Has no registered modules
234/// - Has no configured middleware
235/// - Uses default application configuration
236/// - Has not initiated application startup
237///
238/// # Usage Pattern
239///
240/// ```c
241/// CDMSCAppBuilder* builder = dmsc_app_builder_new();
242/// if (builder == NULL) {
243/// // Handle allocation failure
244/// return ERROR_MEMORY_ALLOCATION;
245/// }
246///
247/// // Register modules and configure
248/// dmsc_app_builder_register_module(builder, http_module);
249/// dmsc_app_builder_register_module(builder, database_module);
250///
251/// // Build and run
252/// dmsc_app_builder_build(builder);
253///
254/// // Cleanup
255/// dmsc_app_builder_free(builder);
256/// ```
257#[no_mangle]
258pub extern "C" fn dmsc_app_builder_new() -> *mut CDMSCAppBuilder {
259 let builder = CDMSCAppBuilder {
260 inner: DMSCAppBuilder::new(),
261 };
262 Box::into_raw(Box::new(builder))
263}
264
265/// Frees a previously allocated CDMSCAppBuilder instance.
266///
267/// Releases all memory associated with the builder including any registered
268/// configurations, module references, or internal state. After this function
269/// returns, the pointer becomes invalid.
270///
271/// # Parameters
272///
273/// - `builder`: Pointer to CDMSCAppBuilder to free. If NULL, the function
274/// returns immediately without error.
275///
276/// # Behavior
277///
278/// The destructor:
279///
280/// - Clears all registered modules
281/// - Releases internal configuration
282/// - Frees allocated memory
283/// - Invalidates the pointer
284///
285/// # Safety
286///
287/// This function is safe to call with NULL. Calling with a pointer that has
288/// already been freed results in undefined behavior.
289#[no_mangle]
290pub extern "C" fn dmsc_app_builder_free(builder: *mut CDMSCAppBuilder) {
291 if !builder.is_null() {
292 unsafe {
293 let _ = Box::from_raw(builder);
294 }
295 }
296}
297
298/// Creates a new CDMSCConfig instance.
299///
300/// Initializes an empty configuration object with no loaded sources.
301/// The configuration starts with default values and requires explicit
302/// loading from configuration sources.
303///
304/// # Returns
305///
306/// Pointer to newly allocated CDMSCConfig on success. Never returns NULL
307/// as the implementation uses infallible construction. The returned pointer
308/// must be freed using dmsc_config_free().
309///
310/// # Initial State
311///
312/// A newly created configuration:
313///
314/// - Contains no loaded values
315/// - Has default values for all known keys
316/// - Has no active configuration sources
317/// - Is not watching for changes
318///
319/// # Usage Pattern
320///
321/// ```c
322/// CDMSCConfig* config = dmsc_config_new();
323/// if (config == NULL) {
324/// // Handle allocation failure
325/// return ERROR_MEMORY_ALLOCATION;
326/// }
327///
328/// // Load from file
329/// int load_result = dmsc_config_load_file(config, "config.yaml");
330/// if (load_result != 0) {
331/// // Handle load failure
332/// }
333///
334/// // Access configuration values
335/// char* host = dmsc_config_get_string(config, "server.host");
336/// int port = dmsc_config_get_int(config, "server.port");
337///
338/// // Cleanup
339/// dmsc_config_free(config);
340/// dmsc_string_free(host);
341/// ```
342#[no_mangle]
343pub extern "C" fn dmsc_config_new() -> *mut CDMSCConfig {
344 let config = CDMSCConfig {
345 inner: DMSCConfig::new(),
346 };
347 Box::into_raw(Box::new(config))
348}
349
350/// Frees a previously allocated CDMSCConfig instance.
351///
352/// Releases all memory associated with the configuration including any
353/// loaded values, watched files, or internal caches. After this function
354/// returns, the pointer becomes invalid.
355///
356/// # Parameters
357///
358/// - `config`: Pointer to CDMSCConfig to free. If NULL, the function returns
359/// immediately without error.
360///
361/// # Behavior
362///
363/// The destructor:
364///
365/// - Clears all configuration values
366/// - Stops file watchers if active
367/// - Releases internal caches
368/// - Invalidates the pointer
369///
370/// # Safety
371///
372/// This function is safe to call with NULL. Calling with a pointer that has
373/// already been freed results in undefined behavior.
374#[no_mangle]
375pub extern "C" fn dmsc_config_free(config: *mut CDMSCConfig) {
376 if !config.is_null() {
377 unsafe {
378 let _ = Box::from_raw(config);
379 }
380 }
381}
382
383/// Retrieves a string configuration value by key.
384///
385/// Looks up the specified key in the configuration hierarchy and returns
386/// the associated string value if found. The function performs type-safe
387/// retrieval with automatic conversion from compatible types.
388///
389/// # Parameters
390///
391/// - `config`: Pointer to CDMSCConfig containing the configuration. Must not
392/// be NULL. If NULL, the function returns NULL.
393/// - `key`: Pointer to null-terminated C string specifying the configuration key.
394/// Keys use dot notation for hierarchical access (e.g., "database.connections.max").
395/// Must not be NULL. If NULL, the function returns NULL.
396///
397/// # Returns
398///
399/// Pointer to newly allocated C string containing the configuration value on
400/// success. The caller is responsible for freeing the returned string using
401/// dmsc_string_free(). Returns NULL if:
402///
403/// - `config` is NULL
404/// - `key` is NULL
405/// - Key does not exist in configuration
406/// - Value exists but is not a string type
407/// - String conversion fails (invalid UTF-8)
408///
409/// # Key Format
410///
411/// Configuration keys support hierarchical access:
412///
413/// - Simple keys: "timeout"
414/// - Nested keys: "server.http.port"
415/// - Array indices: "servers.0.host"
416///
417/// # Example
418///
419/// ```c
420/// char* database_url = dmsc_config_get_string(config, "database.url");
421/// if (database_url != NULL) {
422/// printf("Database URL: %s\n", database_url);
423/// dmsc_string_free(database_url);
424/// } else {
425/// printf("Database URL not configured\n");
426/// }
427/// ```
428///
429/// # Memory Management
430///
431/// The returned string is newly allocated. Callers must release it using
432/// dmsc_string_free() to prevent memory leaks. Do not use free() directly.
433#[no_mangle]
434pub extern "C" fn dmsc_config_get_string(
435 config: *mut CDMSCConfig,
436 key: *const c_char,
437) -> *mut c_char {
438 if config.is_null() || key.is_null() {
439 return std::ptr::null_mut();
440 }
441
442 unsafe {
443 let c = &(*config).inner;
444 let key_str = match std::ffi::CStr::from_ptr(key).to_str() {
445 Ok(s) => s,
446 Err(_) => return std::ptr::null_mut(),
447 };
448
449 match c.get_str(key_str) {
450 Some(val) => match CString::new(val) {
451 Ok(c_str) => c_str.into_raw(),
452 Err(_) => std::ptr::null_mut(),
453 },
454 None => std::ptr::null_mut(),
455 }
456 }
457}