varnish_sys/vcl/
error.rs

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
use std::borrow::Cow;
use std::ffi::CStr;
use std::num::NonZeroUsize;
use std::str::Utf8Error;

// TODO: at some point we may want to add a `txt` variant - e.g. if user wants to handle error creation directly.

/// An `Error` describing all issues with the VCL module
///
/// This enum is used to describe all the possible errors that can happen when working with the VCL module,
/// or converting between Rust and C types.
#[derive(thiserror::Error, Debug)]
pub enum VclError {
    /// Create a new `Error` from a string
    #[error("{0}")]
    String(String),
    /// Create a new `Error` from a string slice
    #[error("{0}")]
    Str(&'static str),
    /// Create a new `VclError` from a C string
    #[error("{}", cstr_to_string(.0))]
    CStr(&'static CStr),
    /// In case Workspace allocation fails
    #[error("Unable to allocate {0} bytes in a Workspace")]
    WsOutOfMemory(NonZeroUsize),
    /// Create a new `VclError` from a UTF-8 error
    #[error("{0}")]
    Utf8Error(#[from] Utf8Error),
    /// Create a new `VclError` from a boxed error
    #[error("{0}")]
    Box(#[from] Box<dyn std::error::Error>),
}

impl VclError {
    /// Create a new `Error` from a string
    pub fn new(s: String) -> Self {
        Self::String(s)
    }

    pub fn as_str(&self) -> Cow<str> {
        match self {
            Self::String(s) => Cow::Borrowed(s.as_str()),
            Self::Utf8Error(e) => Cow::Owned(e.to_string()),
            Self::Str(s) => Cow::Borrowed(s),
            Self::Box(e) => Cow::Owned(e.to_string()),
            Self::CStr(s) => Cow::Owned(cstr_to_string(s)),
            Self::WsOutOfMemory(sz) => {
                Cow::Owned(format!("Unable to allocate {sz} bytes in a Workspace"))
            }
        }
    }
}

fn cstr_to_string(value: &CStr) -> String {
    match value.to_string_lossy() {
        Cow::Borrowed(s) => s.to_string(),
        Cow::Owned(s) => {
            format!("{s} (error is not exact because it contains non-utf8 characters)")
        }
    }
}

// Any error types are done with the #[from] attribute, so we don't need to implement From for them

impl From<String> for VclError {
    fn from(s: String) -> Self {
        Self::String(s)
    }
}

impl From<&'static str> for VclError {
    fn from(s: &'static str) -> Self {
        Self::Str(s)
    }
}

impl From<&'static CStr> for VclError {
    fn from(s: &'static CStr) -> Self {
        Self::CStr(s)
    }
}

/// Shorthand to [`Result<T, VclError>`]
pub type VclResult<T> = Result<T, VclError>;