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
use std::ffi::CStr;
use std::fmt;

use foreign_types::{foreign_type, ForeignType};

use crate::{common::Error as HsError, error::AsResult, ffi};

pub trait AsCompileResult: Sized {
    type Output;
    type Err;

    fn ok_or(self, err: *mut ffi::hs_compile_error_t) -> Result<Self::Output, Self::Err> {
        self.ok_or_else(|| err)
    }

    fn ok_or_else<F>(self, err: F) -> Result<Self::Output, Self::Err>
    where
        F: FnOnce() -> *mut ffi::hs_compile_error_t;
}

impl AsCompileResult for ffi::hs_error_t {
    type Output = ();
    type Err = HsError;

    fn ok_or_else<F>(self, err: F) -> Result<Self::Output, Self::Err>
    where
        F: FnOnce() -> *mut ffi::hs_compile_error_t,
    {
        if self == ffi::HS_SUCCESS as ffi::hs_error_t {
            Ok(())
        } else if self == ffi::HS_COMPILER_ERROR {
            Err(HsError::CompileError(unsafe { Error::from_ptr(err()) }))
        } else {
            Err(HsError::from(self))
        }
    }
}

foreign_type! {
    /// Providing details of the compile error condition.
    pub unsafe type Error: Send + Sync {
        type CType = ffi::hs_compile_error_t;

        fn drop = free_compile_error;
    }
}

unsafe fn free_compile_error(err: *mut ffi::hs_compile_error_t) {
    ffi::hs_free_compile_error(err).expect("free compile error");
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.write_str(self.message())
    }
}

impl fmt::Debug for Error {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("Error")
            .field("message", &self.message())
            .field("expression", &self.expression())
            .finish()
    }
}

impl PartialEq for Error {
    fn eq(&self, other: &Self) -> bool {
        self.as_ptr() == other.as_ptr()
    }
}

impl Eq for Error {}

impl Error {
    unsafe fn as_ref(&self) -> &ffi::hs_compile_error_t {
        self.as_ptr().as_ref().unwrap()
    }

    /// A human-readable error message describing the error.
    pub fn message(&self) -> &str {
        unsafe { CStr::from_ptr(self.as_ref().message).to_str().unwrap() }
    }

    /// The zero-based number of the expression that caused the error (if this can be determined).
    pub fn expression(&self) -> Option<usize> {
        let n = unsafe { self.as_ref().expression };

        if n < 0 {
            None
        } else {
            Some(n as usize)
        }
    }
}