gdnative_sys/
lib.rs

1// For silenced lints/warnings, see also gdnative-bindings/src/lib.rs
2
3// Notes:
4// * deref_nullptr: since rustc 1.53, bindgen causes UB warnings -- see https://github.com/rust-lang/rust-bindgen/issues/1651
5//   remove this once bindgen has fixed the issue (currently at version 1.59.1)
6#![allow(
7    non_upper_case_globals,
8    non_camel_case_types,
9    non_snake_case,
10    improper_ctypes,
11    deref_nullptr,
12    clippy::style
13)]
14include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
15include!(concat!(env!("OUT_DIR"), "/api_wrapper.rs"));
16
17#[derive(Debug)]
18pub enum InitError {
19    VersionMismatch {
20        api_type: GDNATIVE_API_TYPES,
21        want: godot_gdnative_api_version,
22        got: godot_gdnative_api_version,
23    },
24    Generic {
25        message: String,
26    },
27}
28
29fn map_option_to_init_error<T>(t: Option<T>, message: &'static str) -> Result<T, InitError> {
30    match t {
31        Some(t) => Ok(t),
32        None => Err(InitError::Generic {
33            message: message.to_string(),
34        }),
35    }
36}
37
38#[allow(clippy::unnecessary_cast)] // False positives: casts necessary for cross-platform
39unsafe fn find_version(
40    mut api: *const godot_gdnative_api_struct,
41    api_type: GDNATIVE_API_TYPES,
42    version_major: u32,
43    version_minor: u32,
44) -> Option<Result<*const godot_gdnative_api_struct, InitError>> {
45    let mut got = None;
46    if (*api).type_ as u32 == api_type as u32 {
47        while !api.is_null() {
48            // The boolean expression below SHOULD always be true;
49            // we will double check to be safe.
50            if (*api).type_ as u32 == api_type as u32 {
51                let (major, minor) = ((*api).version.major, (*api).version.minor);
52                if major == version_major && minor == version_minor {
53                    return Some(Ok(api));
54                } else {
55                    got = Some(godot_gdnative_api_version { major, minor });
56                }
57            }
58            api = (*api).next;
59        }
60    }
61    got.map(|got| {
62        Err(InitError::VersionMismatch {
63            want: godot_gdnative_api_version {
64                major: version_major,
65                minor: version_minor,
66            },
67            got,
68            api_type,
69        })
70    })
71}
72
73unsafe fn find_api_ptr(
74    core_api: *const godot_gdnative_core_api_struct,
75    api_type: GDNATIVE_API_TYPES,
76    version_major: u32,
77    version_minor: u32,
78) -> Result<*const godot_gdnative_api_struct, InitError> {
79    let mut last_error = None;
80    match find_version(
81        core_api as *const godot_gdnative_api_struct,
82        api_type,
83        version_major,
84        version_minor,
85    ) {
86        Some(Ok(api)) => {
87            return Ok(api);
88        }
89        Some(Err(error)) => {
90            last_error = Some(error);
91        }
92        None => {}
93    }
94    for i in 0..(*core_api).num_extensions {
95        match find_version(
96            *(*core_api).extensions.offset(i as _),
97            api_type,
98            version_major,
99            version_minor,
100        ) {
101            Some(Ok(api)) => {
102                return Ok(api);
103            }
104            Some(Err(error)) => {
105                last_error = Some(error);
106            }
107            None => {}
108        }
109    }
110    Err(last_error.unwrap_or(InitError::Generic {
111        message: format!("Couldn't find API struct with type {}", api_type),
112    }))
113}