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