Skip to main content

openvino_genai_sys/
lib.rs

1//! This crate provides low-level, unsafe, Rust bindings to OpenVINO™ GenAI using its [C API]. If
2//! you are looking to use OpenVINO™ GenAI from Rust, you likely should look at the ergonomic, safe
3//! bindings in [openvino-genai], which depends on this crate. See the repository [README] for more
4//! information, including build instructions.
5//!
6//! [C API]: https://github.com/openvinotoolkit/openvino.genai
7//! [openvino-genai-sys]: https://crates.io/crates/openvino-genai-sys
8//! [openvino-genai]: https://crates.io/crates/openvino-genai
9//! [README]: https://github.com/intel/openvino-rs/tree/main/crates/openvino-genai-sys
10//!
11//! An example interaction with raw [openvino-genai-sys]:
12//! ```no_run
13//! openvino_genai_sys::library::load().expect("to have an OpenVINO GenAI library available");
14//! ```
15
16#![allow(non_snake_case, non_camel_case_types, non_upper_case_globals)]
17#![allow(unused, dead_code)]
18#![deny(clippy::all)]
19#![warn(clippy::pedantic)]
20#![warn(clippy::cargo)]
21#![allow(
22    clippy::must_use_candidate,
23    clippy::suspicious_doc_comments,
24    clippy::wildcard_imports,
25    clippy::doc_markdown
26)]
27
28mod linking;
29
30mod generated;
31pub use generated::*;
32
33// Re-export shared types from openvino-sys so that users of both crates share a single definition.
34pub use openvino_sys::ov_status_e;
35pub use openvino_sys::ov_tensor_t;
36
37/// Contains extra utilities for finding and loading the OpenVINO GenAI shared libraries.
38pub mod library {
39    use std::path::PathBuf;
40
41    /// When compiled with the `runtime-linking` feature, load the function definitions from a
42    /// shared library; with the `dynamic-linking` feature, this function does nothing since the
43    /// library has already been linked.
44    ///
45    /// # Errors
46    ///
47    /// When compiled with the `runtime-linking` feature, this may fail if the `openvino-finder`
48    /// cannot discover the library on the current system.
49    pub fn load() -> Result<(), String> {
50        super::generated::load()?;
51        init_variadic(find().as_deref())
52    }
53
54    /// Load the OpenVINO GenAI shared library from an explicit path.
55    ///
56    /// This is useful when the library is located in a non-standard directory that cannot be
57    /// discovered by the `openvino-finder` search paths or environment variables — for example,
58    /// when the path is read from a configuration file.
59    ///
60    /// The `path` should point to the `openvino_genai_c` shared library file
61    /// (e.g., `libopenvino_genai_c.so`).
62    ///
63    /// # Errors
64    ///
65    /// May fail if the shared library cannot be opened or is invalid.
66    pub fn load_from(path: impl Into<std::path::PathBuf>) -> Result<(), String> {
67        let path = path.into();
68        super::generated::load_from(path.clone())?;
69        init_variadic(Some(&path))
70    }
71
72    /// Initialize the variadic pipeline creation functions from the loaded library.
73    #[allow(unused_variables)]
74    fn init_variadic(path: Option<&std::path::Path>) -> Result<(), String> {
75        #[cfg(feature = "runtime-linking")]
76        if let Some(path) = path {
77            super::runtime_variadic::init_variadic_fns(path)?;
78        }
79        Ok(())
80    }
81
82    /// Return the location of the shared library `openvino-genai-sys` will link to. If compiled
83    /// with runtime linking, this will attempt to discover the location of an `openvino_genai_c`
84    /// shared library on the system. Otherwise (with dynamic linking or compilation from source),
85    /// this relies on a static path discovered at build time.
86    ///
87    /// Knowing the location of the OpenVINO GenAI libraries can be useful for ensuring the correct
88    /// runtime environment is configured.
89    pub fn find() -> Option<PathBuf> {
90        if cfg!(feature = "runtime-linking") {
91            openvino_finder::find("openvino_genai_c", openvino_finder::Linking::Dynamic)
92        } else {
93            Some(PathBuf::from(env!("OPENVINO_GENAI_LIB_PATH")))
94        }
95    }
96}
97
98// The C API exposes variadic pipeline constructors for device property key-value pairs. We provide
99// fixed-signature helpers in both linking modes so higher-level crates can pass a slice of property
100// pointers instead of manually expanding a C varargs list.
101
102const MAX_PROPERTIES: usize = 8;
103
104fn pad_props(
105    props: &[*const ::std::os::raw::c_char],
106) -> [*const ::std::os::raw::c_char; MAX_PROPERTIES * 2] {
107    let mut out = [std::ptr::null(); MAX_PROPERTIES * 2];
108    let n = props.len().min(MAX_PROPERTIES * 2);
109    out[..n].copy_from_slice(&props[..n]);
110    out
111}
112
113#[cfg(feature = "dynamic-linking")]
114mod dynamic_variadic {
115    use super::*;
116
117    unsafe extern "C" {
118        #[link_name = "ov_genai_llm_pipeline_create"]
119        fn ov_genai_llm_pipeline_create_raw(
120            models_path: *const ::std::os::raw::c_char,
121            device: *const ::std::os::raw::c_char,
122            property_args_size: usize,
123            pipe: *mut *mut ov_genai_llm_pipeline,
124            ...
125        ) -> ov_status_e;
126
127        #[link_name = "ov_genai_vlm_pipeline_create"]
128        fn ov_genai_vlm_pipeline_create_raw(
129            models_path: *const ::std::os::raw::c_char,
130            device: *const ::std::os::raw::c_char,
131            property_args_size: usize,
132            pipe: *mut *mut ov_genai_vlm_pipeline,
133            ...
134        ) -> ov_status_e;
135
136        #[link_name = "ov_genai_whisper_pipeline_create"]
137        fn ov_genai_whisper_pipeline_create_raw(
138            models_path: *const ::std::os::raw::c_char,
139            device: *const ::std::os::raw::c_char,
140            property_args_size: usize,
141            pipeline: *mut *mut ov_genai_whisper_pipeline,
142            ...
143        ) -> ov_status_e;
144    }
145
146    /// Create an LLM pipeline (dynamic-linking variant).
147    ///
148    /// `props` contains flattened key-value pairs as C string pointers: `[k1, v1, k2, v2, ...]`.
149    /// Pass an empty slice for no properties. Up to `MAX_PROPERTIES` pairs (16 pointers).
150    ///
151    /// # Safety
152    ///
153    /// The caller must ensure that `models_path`, `device`, and all pointers in `props` are
154    /// valid C strings, and `pipe` is a valid pointer to receive the created pipeline.
155    ///
156    /// # Panics
157    ///
158    /// Panics if `props` contains more than `MAX_PROPERTIES * 2` entries.
159    pub unsafe fn ov_genai_llm_pipeline_create(
160        models_path: *const ::std::os::raw::c_char,
161        device: *const ::std::os::raw::c_char,
162        property_args_size: usize,
163        pipe: *mut *mut ov_genai_llm_pipeline,
164        props: &[*const ::std::os::raw::c_char],
165    ) -> ov_status_e {
166        assert!(
167            props.len() <= MAX_PROPERTIES * 2,
168            "too many properties (max {})",
169            MAX_PROPERTIES
170        );
171        let p = pad_props(props);
172        ov_genai_llm_pipeline_create_raw(
173            models_path,
174            device,
175            property_args_size,
176            pipe,
177            p[0],
178            p[1],
179            p[2],
180            p[3],
181            p[4],
182            p[5],
183            p[6],
184            p[7],
185            p[8],
186            p[9],
187            p[10],
188            p[11],
189            p[12],
190            p[13],
191            p[14],
192            p[15],
193        )
194    }
195
196    /// Create a VLM pipeline (dynamic-linking variant).
197    ///
198    /// See [`ov_genai_llm_pipeline_create`] for details on the `props` parameter.
199    ///
200    /// # Safety
201    ///
202    /// Same safety requirements as [`ov_genai_llm_pipeline_create`].
203    ///
204    /// # Panics
205    ///
206    /// Panics if `props` contains more than `MAX_PROPERTIES * 2` entries.
207    pub unsafe fn ov_genai_vlm_pipeline_create(
208        models_path: *const ::std::os::raw::c_char,
209        device: *const ::std::os::raw::c_char,
210        property_args_size: usize,
211        pipe: *mut *mut ov_genai_vlm_pipeline,
212        props: &[*const ::std::os::raw::c_char],
213    ) -> ov_status_e {
214        assert!(
215            props.len() <= MAX_PROPERTIES * 2,
216            "too many properties (max {})",
217            MAX_PROPERTIES
218        );
219        let p = pad_props(props);
220        ov_genai_vlm_pipeline_create_raw(
221            models_path,
222            device,
223            property_args_size,
224            pipe,
225            p[0],
226            p[1],
227            p[2],
228            p[3],
229            p[4],
230            p[5],
231            p[6],
232            p[7],
233            p[8],
234            p[9],
235            p[10],
236            p[11],
237            p[12],
238            p[13],
239            p[14],
240            p[15],
241        )
242    }
243
244    /// Create a Whisper pipeline (dynamic-linking variant).
245    ///
246    /// See [`ov_genai_llm_pipeline_create`] for details on the `props` parameter.
247    ///
248    /// # Safety
249    ///
250    /// Same safety requirements as [`ov_genai_llm_pipeline_create`].
251    ///
252    /// # Panics
253    ///
254    /// Panics if `props` contains more than `MAX_PROPERTIES * 2` entries.
255    pub unsafe fn ov_genai_whisper_pipeline_create(
256        models_path: *const ::std::os::raw::c_char,
257        device: *const ::std::os::raw::c_char,
258        property_args_size: usize,
259        pipeline: *mut *mut ov_genai_whisper_pipeline,
260        props: &[*const ::std::os::raw::c_char],
261    ) -> ov_status_e {
262        assert!(
263            props.len() <= MAX_PROPERTIES * 2,
264            "too many properties (max {})",
265            MAX_PROPERTIES
266        );
267        let p = pad_props(props);
268        ov_genai_whisper_pipeline_create_raw(
269            models_path,
270            device,
271            property_args_size,
272            pipeline,
273            p[0],
274            p[1],
275            p[2],
276            p[3],
277            p[4],
278            p[5],
279            p[6],
280            p[7],
281            p[8],
282            p[9],
283            p[10],
284            p[11],
285            p[12],
286            p[13],
287            p[14],
288            p[15],
289        )
290    }
291}
292
293#[cfg(feature = "dynamic-linking")]
294pub use dynamic_variadic::{
295    ov_genai_llm_pipeline_create, ov_genai_vlm_pipeline_create, ov_genai_whisper_pipeline_create,
296};
297
298// For runtime linking, we load these functions manually and expose the same fixed-signature
299// helpers as the dynamic-linking path. These use OnceLock so they can be initialized either lazily
300// (from `find()`) or explicitly (from `load_from`). The `library::load()` and
301// `library::load_from()` functions call `init_variadic_fns` to populate them.
302#[cfg(feature = "runtime-linking")]
303mod runtime_variadic {
304    use super::*;
305    use std::path::Path;
306    use std::sync::OnceLock;
307
308    // The C API uses variadic args for property key-value pairs. We define the
309    // function pointer with 16 extra `*const c_char` slots (enough for 8 properties).
310    // The C function only reads `property_args_size * 2` args from the va_list,
311    // so trailing NULLs are harmless.
312    type CreateFn = unsafe extern "C" fn(
313        *const ::std::os::raw::c_char,    // models_path
314        *const ::std::os::raw::c_char,    // device
315        usize,                            // property_args_size (number of key-value pairs)
316        *mut *mut ::std::os::raw::c_void, // pipe
317        // Up to 8 property key-value pairs (16 args):
318        *const ::std::os::raw::c_char,
319        *const ::std::os::raw::c_char,
320        *const ::std::os::raw::c_char,
321        *const ::std::os::raw::c_char,
322        *const ::std::os::raw::c_char,
323        *const ::std::os::raw::c_char,
324        *const ::std::os::raw::c_char,
325        *const ::std::os::raw::c_char,
326        *const ::std::os::raw::c_char,
327        *const ::std::os::raw::c_char,
328        *const ::std::os::raw::c_char,
329        *const ::std::os::raw::c_char,
330        *const ::std::os::raw::c_char,
331        *const ::std::os::raw::c_char,
332        *const ::std::os::raw::c_char,
333        *const ::std::os::raw::c_char,
334    ) -> ov_status_e;
335
336    static LLM_CREATE: OnceLock<CreateFn> = OnceLock::new();
337    static VLM_CREATE: OnceLock<CreateFn> = OnceLock::new();
338    static WHISPER_CREATE: OnceLock<CreateFn> = OnceLock::new();
339
340    /// Initialize the variadic pipeline creation functions from the library at `path`.
341    ///
342    /// Called internally by `library::load()` and `library::load_from()`.
343    pub(crate) fn init_variadic_fns(path: &Path) -> Result<(), String> {
344        unsafe {
345            let lib = libloading::Library::new(path).map_err(|e| {
346                format!(
347                    "failed to open shared library for variadic fns at {}: {}",
348                    path.display(),
349                    e,
350                )
351            })?;
352
353            if let Ok(sym) = lib.get::<CreateFn>(b"ov_genai_llm_pipeline_create") {
354                let _ = LLM_CREATE.set(*sym);
355            }
356            if let Ok(sym) = lib.get::<CreateFn>(b"ov_genai_vlm_pipeline_create") {
357                let _ = VLM_CREATE.set(*sym);
358            }
359            if let Ok(sym) = lib.get::<CreateFn>(b"ov_genai_whisper_pipeline_create") {
360                let _ = WHISPER_CREATE.set(*sym);
361            }
362
363            // Leak the library to keep function pointers valid.
364            std::mem::forget(lib);
365        }
366        Ok(())
367    }
368
369    /// Create an LLM pipeline (runtime-linking variant).
370    ///
371    /// `props` contains flattened key-value pairs as C string pointers: `[k1, v1, k2, v2, ...]`.
372    /// Pass an empty slice for no properties. Up to `MAX_PROPERTIES` pairs (16 pointers).
373    ///
374    /// # Safety
375    ///
376    /// The caller must ensure that `models_path`, `device`, and all pointers in `props` are
377    /// valid C strings, and `pipe` is a valid pointer to receive the created pipeline.
378    ///
379    /// # Panics
380    ///
381    /// Panics if `library::load()` or `library::load_from()` has not been called first,
382    /// or if `props` contains more than `MAX_PROPERTIES * 2` entries.
383    pub unsafe fn ov_genai_llm_pipeline_create(
384        models_path: *const ::std::os::raw::c_char,
385        device: *const ::std::os::raw::c_char,
386        property_args_size: usize,
387        pipe: *mut *mut ov_genai_llm_pipeline,
388        props: &[*const ::std::os::raw::c_char],
389    ) -> ov_status_e {
390        assert!(
391            props.len() <= MAX_PROPERTIES * 2,
392            "too many properties (max {MAX_PROPERTIES})"
393        );
394        let p = pad_props(props);
395        let f = LLM_CREATE
396            .get()
397            .expect("`openvino_genai_c` function not loaded: `ov_genai_llm_pipeline_create`; call library::load() or library::load_from() first");
398        f(
399            models_path,
400            device,
401            property_args_size,
402            pipe.cast(),
403            p[0],
404            p[1],
405            p[2],
406            p[3],
407            p[4],
408            p[5],
409            p[6],
410            p[7],
411            p[8],
412            p[9],
413            p[10],
414            p[11],
415            p[12],
416            p[13],
417            p[14],
418            p[15],
419        )
420    }
421
422    /// Create a VLM pipeline (runtime-linking variant).
423    ///
424    /// See [`ov_genai_llm_pipeline_create`] for details on the `props` parameter.
425    ///
426    /// # Safety
427    ///
428    /// Same safety requirements as [`ov_genai_llm_pipeline_create`].
429    ///
430    /// # Panics
431    ///
432    /// Panics if `library::load()` or `library::load_from()` has not been called first,
433    /// or if `props` contains more than `MAX_PROPERTIES * 2` entries.
434    pub unsafe fn ov_genai_vlm_pipeline_create(
435        models_path: *const ::std::os::raw::c_char,
436        device: *const ::std::os::raw::c_char,
437        property_args_size: usize,
438        pipe: *mut *mut ov_genai_vlm_pipeline,
439        props: &[*const ::std::os::raw::c_char],
440    ) -> ov_status_e {
441        assert!(
442            props.len() <= MAX_PROPERTIES * 2,
443            "too many properties (max {MAX_PROPERTIES})"
444        );
445        let p = pad_props(props);
446        let f = VLM_CREATE
447            .get()
448            .expect("`openvino_genai_c` function not loaded: `ov_genai_vlm_pipeline_create`; call library::load() or library::load_from() first");
449        f(
450            models_path,
451            device,
452            property_args_size,
453            pipe.cast(),
454            p[0],
455            p[1],
456            p[2],
457            p[3],
458            p[4],
459            p[5],
460            p[6],
461            p[7],
462            p[8],
463            p[9],
464            p[10],
465            p[11],
466            p[12],
467            p[13],
468            p[14],
469            p[15],
470        )
471    }
472
473    /// Create a Whisper pipeline (runtime-linking variant).
474    ///
475    /// See [`ov_genai_llm_pipeline_create`] for details on the `props` parameter.
476    ///
477    /// # Safety
478    ///
479    /// Same safety requirements as [`ov_genai_llm_pipeline_create`].
480    ///
481    /// # Panics
482    ///
483    /// Panics if `library::load()` or `library::load_from()` has not been called first,
484    /// or if `props` contains more than `MAX_PROPERTIES * 2` entries.
485    pub unsafe fn ov_genai_whisper_pipeline_create(
486        models_path: *const ::std::os::raw::c_char,
487        device: *const ::std::os::raw::c_char,
488        property_args_size: usize,
489        pipeline: *mut *mut ov_genai_whisper_pipeline,
490        props: &[*const ::std::os::raw::c_char],
491    ) -> ov_status_e {
492        assert!(
493            props.len() <= MAX_PROPERTIES * 2,
494            "too many properties (max {MAX_PROPERTIES})"
495        );
496        let p = pad_props(props);
497        let f = WHISPER_CREATE
498            .get()
499            .expect("`openvino_genai_c` function not loaded: `ov_genai_whisper_pipeline_create`; call library::load() or library::load_from() first");
500        f(
501            models_path,
502            device,
503            property_args_size,
504            pipeline.cast(),
505            p[0],
506            p[1],
507            p[2],
508            p[3],
509            p[4],
510            p[5],
511            p[6],
512            p[7],
513            p[8],
514            p[9],
515            p[10],
516            p[11],
517            p[12],
518            p[13],
519            p[14],
520            p[15],
521        )
522    }
523}
524
525#[cfg(feature = "runtime-linking")]
526pub use runtime_variadic::{
527    ov_genai_llm_pipeline_create, ov_genai_vlm_pipeline_create, ov_genai_whisper_pipeline_create,
528};