use crate::{Result, api, check, sys};
use std::ffi::{CString, c_char};
use std::ptr;
pub fn get_ep_devices(env: &crate::Environment) -> Result<Vec<EpDevice>> {
let mut devices: *const *const sys::EpDeviceHandle = ptr::null();
let mut num: usize = 0;
check(unsafe {
api().get_ep_devices()(
env.as_ptr(),
&mut devices as *mut _ as *const *const *const sys::EpDeviceHandle,
&mut num,
)
})?;
if devices.is_null() || num == 0 {
return Ok(Vec::new());
}
let out = (0..num)
.map(|i| EpDevice {
ptr: unsafe { *devices.add(i) },
})
.collect();
Ok(out)
}
#[derive(Clone, Copy)]
pub struct EpDevice {
ptr: *const sys::EpDeviceHandle,
}
impl EpDevice {
pub fn ep_name(&self) -> Result<String> {
cstr_to_string(unsafe { api().ep_device__ep_name()(self.ptr) })
}
pub fn ep_vendor(&self) -> Result<String> {
cstr_to_string(unsafe { api().ep_device__ep_vendor()(self.ptr) })
}
pub(crate) fn as_ptr(&self) -> *const sys::EpDeviceHandle {
self.ptr
}
}
fn cstr_to_string(p: *const c_char) -> Result<String> {
if p.is_null() {
Ok(String::new())
} else {
unsafe { crate::cstr_to_string(p, "execution provider device string") }
}
}
#[derive(Clone)]
pub(crate) struct EpDeviceAttach {
pub(crate) devices: Vec<*const sys::EpDeviceHandle>,
pub(crate) options: Vec<(CString, CString)>,
}
pub(crate) fn apply_device_attach(
env: &crate::Environment, opts: *mut sys::SessionOptionsHandle, attaches: &[EpDeviceAttach],
) -> Result<()> {
let f = unsafe { api().session_options_append_execution_provider_v2() };
for attach in attaches {
let keys: Vec<*const c_char> = attach.options.iter().map(|(k, _)| k.as_ptr()).collect();
let vals: Vec<*const c_char> = attach.options.iter().map(|(_, v)| v.as_ptr()).collect();
check(unsafe {
f(
opts,
env.as_ptr() as *mut sys::EnvHandle,
attach.devices.as_ptr(),
attach.devices.len(),
keys.as_ptr(),
vals.as_ptr(),
attach.options.len(),
)
})?;
}
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn enumerate_and_attach_ep_devices() {
let env = crate::Environment::new().expect("env");
let devices = get_ep_devices(&env).expect("get_ep_devices");
eprintln!("discovered {} EP device(s):", devices.len());
for d in &devices {
eprintln!(
" - {} ({})",
d.ep_name().expect("ep name"),
d.ep_vendor().expect("ep vendor")
);
}
if devices.is_empty() {
eprintln!("no EP devices registered (CPU-only host) — attach skipped");
return;
}
let opts = crate::SessionOptions::new()
.append_execution_provider_device(&[&devices[0]], &[])
.expect("queue device attach");
let h = opts.build_handle().expect("opts handle");
let r = apply_device_attach(&env, h, &opts.ep_device_attach);
eprintln!(
"apply_device_attach({}) -> {r:?}",
devices[0].ep_name().expect("ep name")
);
unsafe {
crate::api().release_session_options()(h);
}
}
}