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
//! Error types used with Tango.

use std::error;
use std::fmt;
use std::ptr;

use crate::c;
use crate::types::{ErrSeverity, string_from};

/// Convenience alias for a Result from Tango APIs.
pub type TangoResult<R> = Result<R, TangoError>;


/// Represents a single "entry" of a Tango error stack.
#[derive(Debug)]
pub struct TangoFailure {
    pub desc: String,
    pub reason: String,
    pub origin: String,
    pub severity: ErrSeverity,
}

/// A Tango error; corresponds to an exception thrown by the C++ API.
#[derive(Debug)]
pub struct TangoError {
    pub failures: Vec<TangoFailure>,
}

impl fmt::Display for TangoError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "TangoError[\n")?;
        for fail in &self.failures {
            write!(f, "DevFailed[\n")?;
            write!(f, "      desc = {}\n", fail.desc)?;
            write!(f, "    origin = {}\n", fail.origin)?;
            write!(f, "    reason = {}\n", fail.reason)?;
            write!(f, "  severity = {:?}]\n\n", fail.severity)?;
        }
        write!(f, "]\n")
    }
}

impl error::Error for TangoError {
    fn description(&self) -> &str {
        if self.failures.is_empty() {
            ""
        } else {
            &self.failures[0].desc
        }
    }
}

impl TangoError {
    pub(crate) fn from_stack(stackptr: *mut c::ErrorStack) -> TangoError {
        let stack = unsafe  { *stackptr };
        let mut seq = Vec::with_capacity(stack.length as usize);
        for i in 0..stack.length {
            unsafe {
                let df = ptr::read(stack.sequence.offset(i as isize));
                let fail = TangoFailure {
                    desc: string_from(df.desc),
                    reason: string_from(df.reason),
                    origin: string_from(df.origin),
                    severity: ErrSeverity::from_c(df.severity)
                };
                seq.push(fail);
            }
        }
        unsafe { c::tango_free_ErrorStack(stackptr); }
        TangoError { failures: seq }
    }
}