dlsym 0.1.0

Memory-safe bindings around the platform's dynamic library loading primitives
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
//! Intermediate representation of the declarations found in C headers.
//!
//! Names in the IR are final Rust names: the front end resolves typedefs,
//! anonymous types and tag/typedef collisions before handing items over.

/// Every declaration extracted from a set of headers, in emission order.
#[derive(Debug, Clone, Default, PartialEq)]
#[non_exhaustive]
pub struct Header {
    /// Declarations, in source order (types first as needed).
    pub items: Vec<Item>,
}

/// A top-level declaration.
#[derive(Debug, Clone, PartialEq)]
#[non_exhaustive]
pub enum Item {
    /// A function prototype.
    Function(Function),
    /// A global variable.
    Var(Var),
    /// A struct or union.
    Record(Record),
    /// An enum.
    Enum(Enum),
    /// A typedef.
    Typedef(Typedef),
    /// A constant (from a `#define`).
    Const(Const),
    /// A function-like `#define` that wraps a call to a bound function.
    MacroFn(MacroFn),
}

impl Item {
    /// The Rust type this item defines, if any (records, named enums and
    /// typedefs).
    pub fn type_name(&self) -> Option<&str> {
        match self {
            Item::Record(r) => Some(&r.name),
            Item::Enum(e) => e.name.as_deref(),
            Item::Typedef(t) => Some(&t.name),
            _ => None,
        }
    }
}

/// A function-like macro whose body is a single call to a bound function,
/// such as zlib's
/// `#define deflateInit(strm, level) deflateInit_((strm), (level), ZLIB_VERSION, (int)sizeof(z_stream))`.
///
/// It becomes a method that forwards to the function. Parameter types are
/// taken from the parameters of the called function they are passed to.
#[derive(Debug, Clone, PartialEq)]
#[non_exhaustive]
pub struct MacroFn {
    /// The macro's name.
    pub name: String,
    /// The macro's parameter names.
    pub params: Vec<String>,
    /// The called function.
    pub target: String,
    /// The arguments passed to it.
    pub args: Vec<MacroArg>,
}

/// One argument of a [`MacroFn`] call.
#[derive(Debug, Clone, PartialEq)]
#[non_exhaustive]
pub enum MacroArg {
    /// The macro parameter at this index.
    Param(usize),
    /// An integer literal.
    Int(i128),
    /// A string literal (without the terminating NUL).
    Str(Vec<u8>),
    /// A constant (another `#define`), by name.
    Const(String),
    /// `sizeof` a type, by its Rust name.
    SizeOf(String),
}

/// A calling convention.
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash, PartialOrd, Ord)]
#[non_exhaustive]
pub enum Abi {
    /// The platform's C calling convention.
    #[default]
    C,
    /// The C calling convention, for functions that may unwind (C++
    /// functions not declared `noexcept`).
    CUnwind,
    /// `__stdcall` (32-bit Windows).
    Stdcall,
    /// `__fastcall` (32-bit Windows).
    Fastcall,
    /// `__thiscall` (32-bit Windows).
    Thiscall,
    /// `__thiscall`, for C++ member functions that may unwind.
    ThiscallUnwind,
    /// `__vectorcall`.
    Vectorcall,
}

impl Abi {
    /// The ABI string used in `extern "..."`.
    pub fn as_str(self) -> &'static str {
        match self {
            Abi::C => "C",
            Abi::CUnwind => "C-unwind",
            Abi::Stdcall => "stdcall",
            Abi::Fastcall => "fastcall",
            Abi::Thiscall => "thiscall",
            Abi::ThiscallUnwind => "thiscall-unwind",
            Abi::Vectorcall => "vectorcall",
        }
    }
}

/// A function prototype.
#[derive(Debug, Clone, PartialEq)]
#[non_exhaustive]
pub struct Function {
    /// The Rust name (the symbol name for C functions).
    pub name: String,
    /// The symbol name when it differs from `name` (mangled C++ names).
    pub link_name: Option<String>,
    /// The parameters, in order.
    pub params: Vec<Param>,
    /// The return type.
    pub ret: Type,
    /// Whether the function takes `...`.
    pub variadic: bool,
    /// The calling convention.
    pub abi: Abi,
    /// The documentation comment, if any.
    pub doc: Option<String>,
    /// For C++ member functions, constructors and destructors: the class,
    /// whose `this` pointer is the first parameter.
    pub member: Option<Member>,
}

/// The class a C++ member function belongs to.
#[derive(Debug, Clone, PartialEq, Eq)]
#[non_exhaustive]
pub struct Member {
    /// The class's Rust name.
    pub class: String,
    /// What kind of member it is.
    pub kind: MemberKind,
}

/// The kind of a C++ member function.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[non_exhaustive]
pub enum MemberKind {
    /// A non-static member function (`const` ones take `*const` `this`).
    Method,
    /// A constructor (the complete-object one), initializing `this`.
    Constructor,
    /// The destructor (the complete-object one).
    Destructor,
}

/// A function parameter.
#[derive(Debug, Clone, PartialEq)]
#[non_exhaustive]
pub struct Param {
    /// The parameter name, if the prototype gives one.
    pub name: Option<String>,
    /// The parameter type.
    pub ty: Type,
}

/// A global variable exported by the library.
#[derive(Debug, Clone, PartialEq)]
#[non_exhaustive]
pub struct Var {
    /// The Rust name (the symbol name for C variables).
    pub name: String,
    /// The symbol name when it differs from `name` (mangled C++ names).
    pub link_name: Option<String>,
    /// The variable's type.
    pub ty: Type,
    /// Whether the variable is `const`.
    pub is_const: bool,
    /// The documentation comment, if any.
    pub doc: Option<String>,
}

/// Whether a record is a struct or a union.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[non_exhaustive]
pub enum RecordKind {
    /// `struct`
    Struct,
    /// `union`
    Union,
}

/// A struct or union.
#[derive(Debug, Clone, PartialEq)]
#[non_exhaustive]
pub struct Record {
    /// The Rust name.
    pub name: String,
    /// Struct or union.
    pub kind: RecordKind,
    /// The definition, or `None` for an opaque (incomplete) type.
    pub body: Option<RecordBody>,
    /// For a C++ class that is not trivially copyable: its size and
    /// alignment, so that it can be allocated (its fields stay hidden).
    pub opaque_layout: Option<(u64, u64)>,
    /// The documentation comment, if any.
    pub doc: Option<String>,
}

/// The layout and fields of a complete record.
#[derive(Debug, Clone, PartialEq)]
#[non_exhaustive]
pub struct RecordBody {
    /// Size in bytes.
    pub size: u64,
    /// Alignment in bytes.
    pub align: u64,
    /// Fields, in declaration order.
    pub fields: Vec<Field>,
}

/// A record field.
#[derive(Debug, Clone, PartialEq)]
#[non_exhaustive]
pub struct Field {
    /// The Rust name.
    pub name: String,
    /// The field type.
    pub ty: Type,
    /// Offset from the start of the record, in bits.
    pub offset_bits: u64,
    /// Width in bits for bitfields.
    pub bit_width: Option<u32>,
    /// Size and alignment of the field's type in bytes, as computed by the
    /// C compiler (unused for bitfields).
    pub layout: (u64, u64),
    /// Whether the field is a `private` or `protected` C++ member: it is
    /// laid out but not `pub` (and gets no bitfield accessors).
    pub is_private: bool,
    /// The documentation comment, if any.
    pub doc: Option<String>,
}

/// An enum.
#[derive(Debug, Clone, PartialEq)]
#[non_exhaustive]
pub struct Enum {
    /// The Rust name, or `None` for an anonymous enum whose constants are
    /// emitted with the underlying integer type.
    pub name: Option<String>,
    /// The underlying integer type.
    pub repr: Type,
    /// The constants.
    pub variants: Vec<Variant>,
    /// The documentation comment, if any.
    pub doc: Option<String>,
}

/// An enum constant.
#[derive(Debug, Clone, PartialEq)]
#[non_exhaustive]
pub struct Variant {
    /// The constant's name.
    pub name: String,
    /// Its value.
    pub value: i128,
    /// The documentation comment, if any.
    pub doc: Option<String>,
}

/// A typedef.
#[derive(Debug, Clone, PartialEq)]
#[non_exhaustive]
pub struct Typedef {
    /// The Rust name.
    pub name: String,
    /// The aliased type.
    pub ty: Type,
    /// The documentation comment, if any.
    pub doc: Option<String>,
}

/// A constant.
#[derive(Debug, Clone, PartialEq)]
#[non_exhaustive]
pub struct Const {
    /// The constant's name.
    pub name: String,
    /// Its value.
    pub value: ConstValue,
    /// The documentation comment, if any.
    pub doc: Option<String>,
}

/// A constant's value.
#[derive(Debug, Clone, PartialEq)]
#[non_exhaustive]
pub enum ConstValue {
    /// An integer of the given type.
    Int(i128, Type),
    /// A floating-point number of the given type.
    Float(f64, Type),
    /// A string (without the terminating NUL).
    Str(Vec<u8>),
}

/// A C type.
#[derive(Debug, Clone, PartialEq)]
#[non_exhaustive]
pub enum Type {
    /// `void`
    Void,
    /// `_Bool` / `bool`
    Bool,
    /// `char`
    Char,
    /// `signed char`
    SChar,
    /// `unsigned char`
    UChar,
    /// `short`
    Short,
    /// `unsigned short`
    UShort,
    /// `int`
    Int,
    /// `unsigned int`
    UInt,
    /// `long`
    Long,
    /// `unsigned long`
    ULong,
    /// `long long`
    LongLong,
    /// `unsigned long long`
    ULongLong,
    /// `float`
    Float,
    /// `double`
    Double,
    /// A fixed-width integer (`int8_t` … `uint64_t`, `__int128`), as
    /// `(bits, signed)`.
    Fixed(u32, bool),
    /// `size_t` / `uintptr_t`
    USize,
    /// `ssize_t` / `ptrdiff_t` / `intptr_t`
    ISize,
    /// A pointer.
    Pointer {
        /// The pointed-to type.
        pointee: Box<Type>,
        /// Whether the pointee is `const`-qualified.
        is_const: bool,
    },
    /// A fixed-size array.
    Array {
        /// The element type.
        elem: Box<Type>,
        /// The number of elements.
        len: u64,
    },
    /// A function pointer (nullable).
    FnPtr {
        /// Parameter types.
        params: Vec<Type>,
        /// Return type.
        ret: Box<Type>,
        /// Whether it takes `...`.
        variadic: bool,
        /// Calling convention.
        abi: Abi,
    },
    /// A typedef, struct, union or enum, by its Rust name.
    Named(String),
    /// A type with no Rust equivalent (e.g. `long double`); items using it
    /// are skipped.
    Unsupported(String),
}

impl Function {
    /// The name the library exports.
    pub fn symbol(&self) -> &str {
        self.link_name.as_deref().unwrap_or(&self.name)
    }
}

impl Var {
    /// The name the library exports.
    pub fn symbol(&self) -> &str {
        self.link_name.as_deref().unwrap_or(&self.name)
    }
}

impl Type {
    /// Convenience constructor for `T *`.
    pub fn ptr(pointee: Type) -> Self {
        Type::Pointer {
            pointee: Box::new(pointee),
            is_const: false,
        }
    }

    /// Convenience constructor for `const T *`.
    pub fn const_ptr(pointee: Type) -> Self {
        Type::Pointer {
            pointee: Box::new(pointee),
            is_const: true,
        }
    }

    /// Returns the first unsupported type this type contains, if any.
    pub fn unsupported(&self) -> Option<&str> {
        match self {
            Type::Unsupported(what) => Some(what),
            Type::Pointer { pointee, .. } => pointee.unsupported(),
            Type::Array { elem, .. } => elem.unsupported(),
            Type::FnPtr { params, ret, .. } => params
                .iter()
                .chain(std::iter::once(&**ret))
                .find_map(Type::unsupported),
            _ => None,
        }
    }
}