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
use super::*;

use crate::{prefix_type::PrefixRefTrait, utils::leak_value};

/// The root module of a dynamic library,
/// which may contain other modules,function pointers,and static references.
///
///
/// # Examples
///
/// For a more in-context example of a type implementing this trait you can look
/// at either the example in the readme for this crate,
/// or the `example/example_*_interface` crates  in this crates' repository .
///
/// ### Basic
///
/// ```rust
/// use abi_stable::{library::RootModule, sabi_types::VersionStrings, StableAbi};
///
/// #[repr(C)]
/// #[derive(StableAbi)]
/// #[sabi(kind(Prefix(prefix_ref = Module_Ref, prefix_fields = Module_Prefix)))]
/// pub struct Module {
///     pub first: u8,
///     // The `#[sabi(last_prefix_field)]` attribute here means that this is
///     // the last field in this module that was defined in the
///     // first compatible version of the library,
///     #[sabi(last_prefix_field)]
///     pub second: u16,
///     pub third: u32,
/// }
/// impl RootModule for Module_Ref {
///     abi_stable::declare_root_module_statics! {Module_Ref}
///     const BASE_NAME: &'static str = "example_root_module";
///     const NAME: &'static str = "example_root_module";
///     const VERSION_STRINGS: VersionStrings = abi_stable::package_version_strings!();
/// }
///

/// # fn main(){}
/// ```
pub trait RootModule: Sized + StableAbi + PrefixRefTrait + 'static {
    /// The name of the dynamic library,which is the same on all platforms.
    /// This is generally the name of the `implementation crate`.
    const BASE_NAME: &'static str;

    /// The name of the library used in error messages.
    const NAME: &'static str;

    /// The version number of the library that this is a root module of.
    ///
    /// Initialize this with
    /// [`package_version_strings!()`](../macro.package_version_strings.html)
    const VERSION_STRINGS: VersionStrings;

    /// All the constants of this trait and supertraits.
    ///
    /// It can safely be used as a proxy for the associated constants of this trait.
    const CONSTANTS: RootModuleConsts = RootModuleConsts {
        base_name: RStr::from_str(Self::BASE_NAME),
        name: RStr::from_str(Self::NAME),
        version_strings: Self::VERSION_STRINGS,
        layout: IsLayoutChecked::Yes(<Self as StableAbi>::LAYOUT),
        c_abi_testing_fns: crate::library::c_abi_testing::C_ABI_TESTING_FNS,
        _priv: (),
    };

    /// Like `Self::CONSTANTS`,
    /// except without including the type layout constant for the root module.
    const CONSTANTS_NO_ABI_INFO: RootModuleConsts = RootModuleConsts {
        layout: IsLayoutChecked::No,
        ..Self::CONSTANTS
    };

    /// Gets the statics for Self.
    ///
    /// To define this associated function use:
    /// [`abi_stable::declare_root_module_statics!{TypeOfSelf}`
    /// ](../macro.declare_root_module_statics.html).
    /// Passing `Self` instead of `TypeOfSelf` won't work.
    ///
    fn root_module_statics() -> &'static RootModuleStatics<Self>;

    /// Gets the root module,returning None if the module is not yet loaded.
    #[inline]
    fn get_module() -> Option<Self> {
        Self::root_module_statics().root_mod.get()
    }

    /// Gets the RawLibrary of the module,
    /// returning None if the dynamic library failed to load
    /// (it doesn't exist or layout checking failed).
    ///
    /// Note that if the root module is initialized using `Self::load_module_with`,
    /// this will return None even though `Self::get_module` does not.
    ///
    #[inline]
    fn get_raw_library() -> Option<&'static RawLibrary> {
        Self::root_module_statics().raw_lib.get()
    }

    /// Returns the path the library would be loaded from,given a directory(folder).
    fn get_library_path(directory: &Path) -> PathBuf {
        let base_name = Self::BASE_NAME;
        RawLibrary::path_in_directory(directory, base_name, LibrarySuffix::NoSuffix)
    }

    /// Loads the root module,with a closure which either
    /// returns the root module or an error.
    ///
    /// If the root module was already loaded,
    /// this will return the already loaded root module,
    /// without calling the closure.
    fn load_module_with<F, E>(f: F) -> Result<Self, E>
    where
        F: FnOnce() -> Result<Self, E>,
    {
        Self::root_module_statics().root_mod.try_init(f)
    }

    /// Loads this module from the path specified by `where_`,
    /// first loading the dynamic library if it wasn't already loaded.
    ///
    /// Once the root module is loaded,
    /// this will return the already loaded root module.
    ///
    /// # Warning
    ///
    /// If this function is called within a dynamic library,
    /// it must be called either within the root module loader function or
    /// after that function has been called.
    ///
    /// **DO NOT** call this in the static initializer of a dynamic library,
    /// since this library relies on setting up its global state before
    /// calling the root module loader.
    ///
    /// # Errors
    ///
    /// This will return these errors:
    ///
    /// - `LibraryError::OpenError`:
    /// If the dynamic library itself could not be loaded.
    ///
    /// - `LibraryError::GetSymbolError`:
    /// If the root module was not exported.
    ///
    /// - `LibraryError::InvalidAbiHeader`:
    /// If the abi_stable version used by the library is not compatible.
    ///
    /// - `LibraryError::ParseVersionError`:
    /// If the version strings in the library can't be parsed as version numbers,
    /// this can only happen if the version strings are manually constructed.
    ///
    /// - `LibraryError::IncompatibleVersionNumber`:
    /// If the version number of the library is incompatible.
    ///
    /// - `LibraryError::AbiInstability`:
    /// If the layout of the root module is not the expected one.
    ///
    /// - `LibraryError::RootModule` :
    /// If the root module initializer returned an error or panicked.
    ///
    fn load_from(where_: LibraryPath<'_>) -> Result<Self, LibraryError> {
        let statics = Self::root_module_statics();
        statics.root_mod.try_init(|| {
            let lib = statics.raw_lib.try_init(|| -> Result<_, LibraryError> {
                let raw_library = load_raw_library::<Self>(where_)?;

                // if the library isn't leaked
                // it would cause any use of the module to be a use after free.
                //
                // By leaking the library
                // this allows the root module loader to do anything that'd prevent
                // sound library unloading.
                Ok(leak_value(raw_library))
            })?;
            let items = unsafe { lib_header_from_raw_library(lib)? };

            items.ensure_layout::<Self>()?;

            // safety: the layout was checked in the code above,
            unsafe {
                items
                    .init_root_module_with_unchecked_layout::<Self>()?
                    .initialization()
            }
        })
    }

    /// Loads this module from the directory specified by `where_`,
    /// first loading the dynamic library if it wasn't already loaded.
    ///
    /// Once the root module is loaded,
    /// this will return the already loaded root module.
    ///
    /// Warnings and Errors are detailed in [`load_from`](#method.load_from),
    ///
    fn load_from_directory(where_: &Path) -> Result<Self, LibraryError> {
        Self::load_from(LibraryPath::Directory(where_))
    }

    /// Loads this module from the file at `path_`,
    /// first loading the dynamic library if it wasn't already loaded.
    ///
    /// Once the root module is loaded,
    /// this will return the already loaded root module.
    ///
    /// Warnings and Errors are detailed in [`load_from`](#method.load_from),
    ///
    fn load_from_file(path_: &Path) -> Result<Self, LibraryError> {
        Self::load_from(LibraryPath::FullPath(path_))
    }

    /// Defines behavior that happens once the module is loaded.
    ///
    /// This is ran in the `RootModule::load*` associated functions
    /// after the root module has succesfully been loaded.
    ///
    /// The default implementation does nothing.
    fn initialization(self) -> Result<Self, LibraryError> {
        Ok(self)
    }
}

/// Loads the raw library at `where_`
fn load_raw_library<M>(where_: LibraryPath<'_>) -> Result<RawLibrary, LibraryError>
where
    M: RootModule,
{
    let path = match where_ {
        LibraryPath::Directory(directory) => M::get_library_path(directory),
        LibraryPath::FullPath(full_path) => full_path.to_owned(),
    };
    RawLibrary::load_at(&path)
}

/// Gets the LibHeader of a library.
///
/// # Errors
///
/// This will return these errors:
///
/// - `LibraryError::GetSymbolError`:
/// If the root module was not exported.
///
/// - `LibraryError::InvalidAbiHeader`:
/// If the abi_stable used by the library is not compatible.
///
/// # Safety
///
/// The LibHeader is implicitly tied to the lifetime of the library,
/// it will contain dangling `'static` references if the library is dropped before it does.
///
///
pub unsafe fn lib_header_from_raw_library(
    raw_library: &RawLibrary,
) -> Result<&'static LibHeader, LibraryError> {
    unsafe { abi_header_from_raw_library(raw_library)?.upgrade() }
}

/// Gets the AbiHeaderRef of a library.
///
/// # Errors
///
/// This will return these errors:
///
/// - `LibraryError::GetSymbolError`:
/// If the root module was not exported.
///
/// # Safety
///
/// The AbiHeaderRef is implicitly tied to the lifetime of the library,
/// it will contain dangling `'static` references if the library is dropped before it does.
///
///
pub unsafe fn abi_header_from_raw_library(
    raw_library: &RawLibrary,
) -> Result<AbiHeaderRef, LibraryError> {
    let mangled = ROOT_MODULE_LOADER_NAME_WITH_NUL;
    let header: AbiHeaderRef = unsafe { *raw_library.get::<AbiHeaderRef>(mangled.as_bytes())? };

    Ok(header)
}

/// Gets the LibHeader of the library at the path.
///
/// This leaks the underlying dynamic library,
/// if you need to do this without leaking you'll need to use
/// `lib_header_from_raw_library` instead.
///
/// # Errors
///
/// This will return these errors:
///
/// - `LibraryError::OpenError`:
/// If the dynamic library itself could not be loaded.
///
/// - `LibraryError::GetSymbolError`:
/// If the root module was not exported.
///
/// - `LibraryError::InvalidAbiHeader`:
/// If the abi_stable version used by the library is not compatible.
///
///
pub fn lib_header_from_path(path: &Path) -> Result<&'static LibHeader, LibraryError> {
    let raw_lib = RawLibrary::load_at(path)?;

    let library_getter = unsafe { lib_header_from_raw_library(&raw_lib)? };

    mem::forget(raw_lib);

    Ok(library_getter)
}

/// Gets the AbiHeaderRef of the library at the path.
///
/// This leaks the underlying dynamic library,
/// if you need to do this without leaking you'll need to use
/// `lib_header_from_raw_library` instead.
///
/// # Errors
///
/// This will return these errors:
///
/// - `LibraryError::OpenError`:
/// If the dynamic library itself could not be loaded.
///
/// - `LibraryError::GetSymbolError`:
/// If the root module was not exported.
///
///
pub fn abi_header_from_path(path: &Path) -> Result<AbiHeaderRef, LibraryError> {
    let raw_lib = RawLibrary::load_at(path)?;

    let library_getter = unsafe { abi_header_from_raw_library(&raw_lib)? };

    mem::forget(raw_lib);

    Ok(library_getter)
}

//////////////////////////////////////////////////////////////////////

macro_rules! declare_root_module_consts {
    (
        fields=[
            $(
                $(#[$field_meta:meta])*
                method_docs=$method_docs:expr,
                $field:ident : $field_ty:ty
            ),* $(,)*
        ]
    ) => (
        /// All the constants of the [`RootModule`] trait for some erased type.
        ///
        /// [`RootModule`]: ./trait.RootModule.html
        #[repr(C)]
        #[derive(StableAbi,Copy,Clone)]
        pub struct RootModuleConsts{
            $(
                $(#[$field_meta])*
                $field : $field_ty,
            )*
            _priv:(),
        }

        impl RootModuleConsts{
            $(
                #[doc=$method_docs]
                pub const fn $field(&self)->$field_ty{
                    self.$field
                }
            )*
        }

    )
}

declare_root_module_consts! {
    fields=[
        method_docs="
         The name of the dynamic library,which is the same on all platforms.
         This is generally the name of the implementation crate.",
        base_name: RStr<'static>,

        method_docs="The name of the library used in error messages.",
        name: RStr<'static>,

        method_docs="The version number of the library this was created from.",
        version_strings: VersionStrings,

        method_docs="The (optional) type layout constant of the root module.",
        layout: IsLayoutChecked,

        method_docs="\
         Functions used to test that the C abi is the same in both the library 
         and the loader\
        ",
        c_abi_testing_fns:&'static CAbiTestingFns,
    ]
}