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
use super::{
    lib_header::AbiHeader,
    root_mod_trait::RootModule,
};

use crate::{
    sabi_types::{ParseVersionError, VersionNumber, VersionStrings},
    std_types::{RBoxError, RResult, RVec},
};

use std::{
    fmt::{self, Display},
    path::PathBuf,
};

#[allow(unused_imports)]
use core_extensions::SelfOps;


/// All the possible errors that could happen when loading a library,
/// or a module.
#[derive(Debug)]
pub enum LibraryError {
    /// When a library can't be loaded, because it doesn't exist.
    OpenError{
        path:PathBuf,
        err: Box<libloading::Error>,
    },
    /// When a function/static does not exist.
    GetSymbolError{
        library:PathBuf,
        /// The name of the function/static.Does not have to be utf-8.
        symbol:Vec<u8>,
        err: Box<libloading::Error>,
    },
    /// The version string could not be parsed into a version number.
    ParseVersionError(ParseVersionError),
    /// The version numbers of the library was incompatible.
    IncompatibleVersionNumber {
        library_name: &'static str,
        expected_version: VersionNumber,
        actual_version: VersionNumber,
    },
    RootModule{
        err: RootModuleError,
        module_name: &'static str,
        version: VersionStrings,
    },
    /// The abi is incompatible.
    /// The error is opaque,since the error always comes from the main binary
    /// (dynamic libraries can be loaded from other dynamic libraries).
    AbiInstability(RBoxError),
    /// The type used to check that this is a compatible abi_stable
    /// is not the same.
    InvalidAbiHeader(AbiHeader),
    /// When Rust changes how it implements the C abi,
    InvalidCAbi{
        expected:RBoxError,
        found:RBoxError,
    },
    /// There could have been 0 or more errors in the function.
    Many(RVec<Self>),
}

impl From<ParseVersionError> for LibraryError {
    fn from(v: ParseVersionError) -> LibraryError {
        LibraryError::ParseVersionError(v)
    }
}

impl Display for LibraryError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.write_str("\n")?;
        match self {
            LibraryError::OpenError{path,err} => writeln!(
                f,
                "Could not open library at:\n\t{}\nbecause:\n\t{}",
                path.display(),err
            ),
            LibraryError::GetSymbolError{library,symbol,err} => writeln!(
                f,
                "Could load symbol:\n\t{}\nin library:\n\t{}\nbecause:\n\t{}",
                String::from_utf8_lossy(symbol),
                library.display(),
                err
            ),
            LibraryError::ParseVersionError(x) => fmt::Display::fmt(x, f),
            LibraryError::IncompatibleVersionNumber {
                library_name,
                expected_version,
                actual_version,
            } => writeln!(
                f,
                "\n'{}' library version mismatch:\nuser:{}\nlibrary:{}",
                library_name, expected_version, actual_version,
            ),
            LibraryError::RootModule{err,module_name,version} => {
                writeln!(f, "An error ocurred while loading this library:\t\n{}", module_name)?;
                writeln!(f, "version:\n\t{}", version)?;
                f.write_str("the error:\n\n")?;
                fmt::Display::fmt(err, f)
            },
            LibraryError::AbiInstability(x) => fmt::Display::fmt(x, f),
            LibraryError::InvalidAbiHeader(found) => write!(
                f,
                "The abi of the library was:\n{:#?}\n\
                 When this library expected:\n{:#?}",
                found, AbiHeader::VALUE,
            ),
            LibraryError::InvalidCAbi{expected,found}=>{
                write!{
                    f,
                    "The C abi of the library is different than expected:\n\
                     While running tests on the library:\n\
                         Found:\n        {found}\n\
                         Expected:\n        {expected}\n\
                    ",
                    found=found,
                    expected=expected,
                }
            },
            LibraryError::Many(list)=>{
                for e in list {
                    Display::fmt(e,f)?;
                }
                Ok(())
            }
        }?;
        f.write_str("\n")?;
        Ok(())
    }
}

impl ::std::error::Error for LibraryError {}


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


/// The errors that a `#[export_root_module]` function can return.
#[repr(u8)]
#[derive(Debug, StableAbi)]
pub enum RootModuleError{
    Returned(RBoxError),
    Unwound,
}

impl RootModuleError{
    /// Reallocates the error using the current global allocator,
    /// to ensure that there is no pointer into the dynamic library.
    pub fn reallocate(&mut self){
        match self {
            Self::Returned(e)=>{
                *e = e.to_formatted_error();
            },
            Self::Unwound=>{}
        }
    }

    /// Converts this `RootModuleError` into a `LibraryError`,
    /// with metadata about the module that failed to load.
    pub fn into_library_error<M: RootModule>(self) -> LibraryError {
        LibraryError::RootModule{
            err: self,
            module_name: M::NAME,
            version: M::VERSION_STRINGS,
        }
    }
}

impl Display for RootModuleError{
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.write_str("\n")?;
        match self {
            Self::Returned(e)=>Display::fmt(e, f)?,
            Self::Unwound=>f.write_str("the root module loader panicked")?,
        }
        f.write_str("\n")?;
        Ok(())
    }
}

impl ::std::error::Error for RootModuleError {}


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


/// For converting the return value of a `#[export_root_module]` function
/// to a `Result<(), RootModuleError>`.
pub trait IntoRootModuleResult {
    /// The module that is loaded in the success case.
    type Module: RootModule;
    
    /// Performs the conversion
    fn into_root_module_result(self) -> Result<Self::Module, RootModuleError>;
}

impl<M: RootModule> IntoRootModuleResult for Result<M, RBoxError> {
    type Module = M;
    
    fn into_root_module_result(self) -> Result<M, RootModuleError> {
        self.map_err(RootModuleError::Returned)
    }
}

impl<M: RootModule> IntoRootModuleResult for RResult<M, RBoxError> {
    type Module = M;
    
    fn into_root_module_result(self) -> Result<M, RootModuleError> {
        self.into_result()
            .map_err(RootModuleError::Returned)
    }
}

impl<M: RootModule> IntoRootModuleResult for M {
    type Module = M;

    fn into_root_module_result(self) -> Result<M, RootModuleError> {
        Ok(self)
    }
}


#[cfg(test)]
mod tests{
    use super::*;

    use crate::{
        for_examples::{Module, Module_Ref},
        prefix_type::{PrefixTypeTrait, WithMetadata},
        std_types::{RBox, RSome, RErr, ROk},
    };

    use std::fmt::Error as FmtError;

    const MOD_WM: &WithMetadata<Module> = &WithMetadata::new(PrefixTypeTrait::METADATA, Module {
        first: RSome(5),
        second: rstr!(""),
        third: 13,
    });

    // `const PREFIX` can have different address every time it's used,
    // to fix that I made it a static
    static PREFIX: Module_Ref = Module_Ref(MOD_WM.static_as_prefix());

    #[test]
    fn into_root_module_result_test() {
        type Res = Result<Module_Ref, RBoxError>;
        type RRes = RResult<Module_Ref, RBoxError>;
        
        {
            assert_eq!(
                PREFIX.into_root_module_result().unwrap().0.to_raw_ptr() as usize,
                PREFIX.0.to_raw_ptr() as usize,
            );
        }

        fn test_case(
            ok: Result<Module_Ref, RootModuleError>,
            err: Result<Module_Ref, RootModuleError>,
        ){
            assert_eq!(ok.unwrap().0.to_raw_ptr() as usize, PREFIX.0.to_raw_ptr() as usize);            

            let downcasted = match err.err().unwrap() {
                RootModuleError::Returned(x)=>x.downcast::<FmtError>().unwrap(),
                RootModuleError::Unwound=>unreachable!(),
            };
            assert_eq!(downcasted, RBox::new(FmtError));
        }

        // From Result
        {
            let ok: Res = Ok(PREFIX);
            let err: Res = Err(RBoxError::new(FmtError));

            test_case(ok.into_root_module_result(), err.into_root_module_result());
        }

        // From RResult
        {
            let ok: RRes = ROk(PREFIX);
            let err: RRes = RErr(RBoxError::new(FmtError));

            test_case(ok.into_root_module_result(), err.into_root_module_result());
            
        }
    }
}