Skip to main content

mono_rt/types/
image.rs

1use std::ffi::{CStr, CString};
2use std::ptr;
3
4use super::{MonoClass, mono_handle};
5use crate::{MonoError, Result, api};
6
7struct FindContext<'a> {
8    target_name: &'a str,
9    result: Option<MonoImage>,
10    api_failed: bool,
11}
12
13mono_handle!(MonoImage);
14
15impl MonoImage {
16    /// Finds a loaded assembly image by name.
17    ///
18    /// # Errors
19    ///
20    /// Returns [`MonoError::Uninitialized`] if the Mono API has not been initialized.
21    pub fn find(name: &str) -> Result<Option<Self>> {
22        let mut ctx = FindContext {
23            target_name: name,
24            result: None,
25            api_failed: false,
26        };
27        api()?.assembly_foreach(find_image_callback, ptr::addr_of_mut!(ctx).cast());
28        if ctx.api_failed {
29            return Err(MonoError::Uninitialized);
30        }
31        Ok(ctx.result)
32    }
33
34    /// Resolves a class in this image by namespace and name.
35    ///
36    /// # Errors
37    ///
38    /// Returns [`MonoError::NullByteInName`] if `namespace` or `name` contain an interior null byte.
39    /// Returns [`MonoError::Uninitialized`] if the Mono API has not been initialized.
40    pub fn class_from_name(self, namespace: &str, name: &str) -> Result<Option<MonoClass>> {
41        let ns = CString::new(namespace).map_err(|_| MonoError::NullByteInName)?;
42        let nm = CString::new(name).map_err(|_| MonoError::NullByteInName)?;
43        let ptr = api()?.class_from_name(self.as_ptr(), ns.as_ptr(), nm.as_ptr());
44        Ok(MonoClass::from_ptr(ptr))
45    }
46}
47
48/// Callback for `mono_assembly_foreach` to find an image by name.
49///
50/// # Safety
51///
52/// `assembly` must be a valid `MonoAssembly*` and `user_data` must be a valid pointer to a
53/// `FindContext`, both on a Mono-attached thread.
54unsafe extern "C" fn find_image_callback(assembly: *mut c_void, user_data: *mut c_void) {
55    let Ok(api) = api() else {
56        let ctx = unsafe { &mut *user_data.cast::<FindContext<'_>>() };
57        ctx.api_failed = true;
58        return;
59    };
60
61    let ctx = unsafe { &mut *user_data.cast::<FindContext<'_>>() };
62    if ctx.result.is_some() {
63        return;
64    }
65
66    let image = api.assembly_get_image(assembly);
67    if image.is_null() {
68        return;
69    }
70
71    let name_ptr = api.image_get_name(image);
72    if name_ptr.is_null() {
73        return;
74    }
75
76    let name = unsafe { CStr::from_ptr(name_ptr) }.to_str().unwrap_or("");
77    if name == ctx.target_name {
78        ctx.result = Some(unsafe { MonoImage::from_ptr_unchecked(image) });
79    }
80}