Skip to main content

libxml_rs/abi/
versioning.rs

1//! C ABI versioning — LIBXML2_VERSION, LIBXSLT_VERSION, runtime version APIs (§83, §84).
2//!
3//! This module implements the public C ABI version functions:
4//! - `xmlLibxmlVersion()` — returns LIBXML2_VERSION as integer
5//! - `xmlLibxmlVersionString()` — returns LIBXML2_VERSION string pointer
6//! - `xmlParserVersion()` — alias for xmlLibxmlVersionString
7//! - `xmlCheckVersion()` — runtime version compatibility check
8//! - `xsltLibxsltVersion()` — returns LIBXSLT_VERSION as integer
9//! - `xsltLibxsltVersionString()` — returns LIBXSLT_VERSION string pointer
10//! - `xsltCheckVersion()` — runtime XSLT version compatibility check
11//!
12//! # Phase 1 status
13//!
14//! Complete — all version APIs are implemented.
15//!
16//! # Compatibility profile
17//!
18//! Currently targeting libxml2 2.12.0 / libxslt 1.1.39 compatibility.
19//! These versions are selected as the first modern stable release after
20//! the major 2.11 → 2.12 API transition.
21//!
22//! # UPSTREAM-PARITY
23//!
24//! Upstream version format: major * 10000 + minor * 100 + micro
25//! Example: 2.12.0 → 21200
26
27#![allow(non_upper_case_globals)]
28
29use core::ffi::c_char;
30use core::ptr;
31use core::sync::atomic::AtomicBool;
32use core::sync::atomic::Ordering;
33use std::os::raw::c_int;
34
35use crate::abi::types::*;
36
37// ═══════════════════════════════════════════════════════════════════════════════
38// Target Version Constants
39// ═══════════════════════════════════════════════════════════════════════════════
40
41/// The target libxml2 version we aim to be compatible with.
42const TARGET_LIBXML2_MAJOR: c_int = 2;
43const TARGET_LIBXML2_MINOR: c_int = 12;
44const TARGET_LIBXML2_MICRO: c_int = 0;
45
46/// The target libxslt version we aim to be compatible with.
47const TARGET_LIBXSLT_MAJOR: c_int = 1;
48const TARGET_LIBXSLT_MINOR: c_int = 1;
49const TARGET_LIBXSLT_MICRO: c_int = 39;
50
51/// The version string for libxml2 compatibility.
52const LIBXML2_VERSION_STRING: &[u8; 7] = b"2.12.0\0";
53
54/// The version string for libxslt compatibility.
55const LIBXSLT_VERSION_STRING: &[u8; 7] = b"1.1.39\0";
56
57// ═══════════════════════════════════════════════════════════════════════════════
58// Version Macros (also defined in types.rs for compile-time use)
59// ═══════════════════════════════════════════════════════════════════════════════
60
61/// Compute the numeric version from major/minor/micro components.
62#[inline]
63pub const fn version_number(major: c_int, minor: c_int, micro: c_int) -> c_int {
64    major * 10000 + minor * 100 + micro
65}
66
67/// libxml2 version as a number: 2 * 10000 + 12 * 100 + 0 = 21200
68pub const LIBXML2_VERSION_NUM: c_int = version_number(
69    TARGET_LIBXML2_MAJOR,
70    TARGET_LIBXML2_MINOR,
71    TARGET_LIBXML2_MICRO,
72);
73
74/// libxslt version as a number: 1 * 10000 + 1 * 100 + 39 = 10139
75pub const LIBXSLT_VERSION_NUM: c_int = version_number(
76    TARGET_LIBXSLT_MAJOR,
77    TARGET_LIBXSLT_MINOR,
78    TARGET_LIBXSLT_MICRO,
79);
80
81// ═══════════════════════════════════════════════════════════════════════════════
82// Initialization Tracking
83// ═══════════════════════════════════════════════════════════════════════════════
84
85/// Whether the library has been initialized.
86static INITIALIZED: AtomicBool = AtomicBool::new(false);
87
88/// Mark the library as initialized.
89pub fn set_initialized() {
90    INITIALIZED.store(true, Ordering::Release);
91}
92
93/// Check whether the library has been initialized.
94pub fn is_initialized() -> bool {
95    INITIALIZED.load(Ordering::Acquire)
96}
97
98// ═══════════════════════════════════════════════════════════════════════════════
99// libxml2 Version Functions
100// ═══════════════════════════════════════════════════════════════════════════════
101
102/// Return the libxml2 version as an integer.
103///
104/// Returns `major * 10000 + minor * 100 + micro`.
105///
106/// # UPSTREAM-PARITY
107///
108/// ```c
109/// int xmlLibxmlVersion(void);
110/// ```
111///
112/// Oracle behavior (2.12.0): returns 21200.
113pub fn xmlLibxmlVersion() -> c_int {
114    LIBXML2_VERSION_NUM
115}
116
117/// Return the libxml2 version as a static C string.
118///
119/// # UPSTREAM-PARITY
120///
121/// ```c
122/// const char *xmlLibxmlVersionString(void);
123/// ```
124///
125/// Oracle behavior (2.12.0): returns pointer to "2.12.0".
126pub fn xmlLibxmlVersionString() -> *const c_char {
127    LIBXML2_VERSION_STRING.as_ptr() as *const c_char
128}
129
130/// Return the parser version string (alias for `xmlLibxmlVersionString`).
131///
132/// # UPSTREAM-PARITY
133///
134/// ```c
135/// const char *xmlParserVersion(void);
136/// ```
137pub fn xmlParserVersion() -> *const c_char {
138    xmlLibxmlVersionString()
139}
140
141/// Check that the library version is at least `version`.
142///
143/// # Returns
144///
145/// - 0 if the library version is >= `version`
146/// - -1 if the library version is < `version`
147///
148/// # UPSTREAM-PARITY
149///
150/// ```c
151/// int xmlCheckVersion(int version);
152/// ```
153///
154/// Oracle behavior: compares LIBXML2_VERSION (compiled-in) against `version`.
155/// Returns 0 if compatible, -1 if not.
156pub fn xmlCheckVersion(version: c_int) -> c_int {
157    if LIBXML2_VERSION_NUM >= version {
158        0
159    } else {
160        -1
161    }
162}
163
164// ═══════════════════════════════════════════════════════════════════════════════
165// libxslt Version Functions
166// ═══════════════════════════════════════════════════════════════════════════════
167
168/// Return the libxslt version as an integer.
169///
170/// Returns `major * 10000 + minor * 100 + micro`.
171///
172/// # UPSTREAM-PARITY
173///
174/// ```c
175/// int xsltLibxsltVersion(void);
176/// ```
177pub fn xsltLibxsltVersion() -> c_int {
178    LIBXSLT_VERSION_NUM
179}
180
181/// Return the libxslt version as a static C string.
182///
183/// # UPSTREAM-PARITY
184///
185/// ```c
186/// const char *xsltLibxsltVersionString(void);
187/// ```
188pub fn xsltLibxsltVersionString() -> *const c_char {
189    LIBXSLT_VERSION_STRING.as_ptr() as *const c_char
190}
191
192/// Convert a C string pointer to a byte slice (NULL-safe).
193///
194/// # SAFETY
195///
196/// - `ptr` must be a valid null-terminated C string or NULL.
197pub unsafe fn c_str_to_bytes<'a>(ptr: *const c_char) -> Option<&'a [u8]> {
198    if ptr.is_null() {
199        return None;
200    }
201    let len = unsafe { libc::strlen(ptr) };
202    Some(unsafe { core::slice::from_raw_parts(ptr as *const u8, len) })
203}
204
205/// Check that the XSLT library version is at least `version`.
206///
207/// # Returns
208///
209/// - 0 if the library version is >= `version`
210/// - -1 if the library version is < `version`
211///
212/// # UPSTREAM-PARITY
213///
214/// ```c
215/// int xsltCheckVersion(int version);
216/// ```
217pub fn xsltCheckVersion(version: c_int) -> c_int {
218    if LIBXSLT_VERSION_NUM >= version {
219        0
220    } else {
221        -1
222    }
223}
224
225// ═══════════════════════════════════════════════════════════════════════════════
226// Feature Detection
227// ═══════════════════════════════════════════════════════════════════════════════
228
229// ═══════════════════════════════════════════════════════════════════════════════
230// Compile-time Version Macros (for Rust consumers)
231// ═══════════════════════════════════════════════════════════════════════════════
232
233/// The libxml2 version as a number (compile-time constant).
234pub const LIBXML2_VERSION: c_int = LIBXML2_VERSION_NUM;
235
236/// The libxml2 version major number.
237pub const LIBXML2_VERSION_MAJOR: c_int = TARGET_LIBXML2_MAJOR;
238
239/// The libxml2 version minor number.
240pub const LIBXML2_VERSION_MINOR: c_int = TARGET_LIBXML2_MINOR;
241
242/// The libxml2 version micro number.
243pub const LIBXML2_VERSION_MICRO: c_int = TARGET_LIBXML2_MICRO;
244
245/// The libxml2 version as a number (alternate name).
246pub const LIBXML2_VERSION_NUMBER: c_int = LIBXML2_VERSION_NUM;
247
248/// Extra version suffix (empty string for release versions).
249pub const LIBXML2_VERSION_EXTRA: &[u8; 1] = b"\0";
250
251/// The libxslt version as a number (compile-time constant).
252pub const LIBXSLT_VERSION: c_int = LIBXSLT_VERSION_NUM;
253
254/// The libxslt version major number.
255pub const LIBXSLT_VERSION_MAJOR: c_int = TARGET_LIBXSLT_MAJOR;
256
257/// The libxslt version minor number.
258pub const LIBXSLT_VERSION_MINOR: c_int = TARGET_LIBXSLT_MINOR;
259
260/// The libxslt version micro number.
261pub const LIBXSLT_VERSION_MICRO: c_int = TARGET_LIBXSLT_MICRO;
262
263/// The libxslt version as a number (alternate name).
264pub const LIBXSLT_VERSION_NUMBER: c_int = LIBXSLT_VERSION_NUM;
265
266/// Extra version suffix for libxslt (empty string for release versions).
267pub const LIBXSLT_VERSION_EXTRA: &[u8; 1] = b"\0";
268
269// ═══════════════════════════════════════════════════════════════════════════════
270// Tests