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
//! Common structures between the environment and the SDK.
//! This crate omits the structures that are shared between
//! Zephyr and Mercury due to the latter's closed-source nature.

pub mod wrapping;
pub mod http;
pub mod log;

pub fn to_fixed<T, const N: usize>(v: Vec<T>) -> [T; N] {
    v.try_into()
        .unwrap_or_else(|v: Vec<T>| panic!("Expected a Vec of length {} but it was {}", N, v.len()))
}

#[repr(u32)]
pub enum ZephyrStatus {
    Unknown = 0,
    Success = 1,
    DbWriteError = 2,
    DbReadError = 3,
    NoValOnStack = 4,
    HostConfiguration = 5
}

use http::AgnosticRequest;
use log::ZephyrLog;
use serde::{Deserialize, Serialize};
use soroban_sdk::xdr::{LedgerEntry, ScAddress, ScVal};
use thiserror::Error;

#[derive(Error, Debug)]
pub enum DatabaseError {
    #[error("Invalid permissions. Tried reading when in write-only")]
    ReadOnWriteOnly,

    #[error("Invalid permissions. Tried writing when in read-only")]
    WriteOnReadOnly,

    #[error("Zephyr query malformed.")]
    ZephyrQueryMalformed,

    #[error("Zephyr query error.")]
    ZephyrQueryError,

    #[error("Unable to write to DB.")]
    WriteError,

    #[error("Unable to parse operator.")]
    OperatorError,
}


impl From<anyhow::Error> for ZephyrStatus {
    fn from(value: anyhow::Error) -> Self {
        match value.downcast_ref() {
            Some(DatabaseError::WriteError) => ZephyrStatus::DbWriteError,
            Some(DatabaseError::ZephyrQueryError) => ZephyrStatus::DbReadError,
            Some(DatabaseError::ZephyrQueryMalformed) => ZephyrStatus::DbReadError,
            Some(DatabaseError::ReadOnWriteOnly) => ZephyrStatus::HostConfiguration,
            Some(DatabaseError::WriteOnReadOnly) => ZephyrStatus::HostConfiguration,
            Some(DatabaseError::OperatorError) => ZephyrStatus::DbWriteError, // todo: specific error
            None => ZephyrStatus::Unknown
        } 
    }
}

impl From<u32> for ZephyrStatus {
    fn from(value: u32) -> Self {
        match value {
            0 => Self::Unknown,
            1 => Self::Success,
            2 => Self::DbWriteError,
            3 => Self::DbReadError,
            4 => Self::NoValOnStack,
            5 => Self::HostConfiguration,
            _ => panic!("Unrecoverable status"),
        }
    }
}

#[derive(Deserialize, Serialize, Clone)]
pub enum ZephyrVal {
    I128(i128),
    I64(i64),
    U64(u64),
    F64(f64),
    U32(u32),
    I32(i32),
    F32(f32),
    String(String),
    Bytes(Vec<u8>)
}

#[derive(Debug)]
pub enum ZephyrValError {
    ConversionError
}

#[derive(Debug, Deserialize, Serialize, Clone)]
pub struct ContractDataEntry {
    pub contract_id: ScAddress,
    pub key: ScVal,
    pub entry: LedgerEntry,
    pub durability: i32,
    pub last_modified: i32
}

macro_rules! impl_inner_from {
    ($variant:ident, $inner:ty) => {
        impl From<$inner> for ZephyrVal {
            fn from(value: $inner) -> Self {
                ZephyrVal::$variant(value)
            }
        }

        impl From<ZephyrVal> for $inner {
            fn from(value: ZephyrVal) -> Self {
                match value {
                    ZephyrVal::$variant(inner_val) => inner_val,
                    _ => panic!("Attempted to convert ZephyrVal variant to different inner type"),
                }
            }
        }
    };
}

impl_inner_from!(I128, i128);
impl_inner_from!(I64, i64);
impl_inner_from!(U64, u64);
impl_inner_from!(F64, f64);
impl_inner_from!(U32, u32);
impl_inner_from!(I32, i32);
impl_inner_from!(F32, f32);
impl_inner_from!(String, String);
impl_inner_from!(Bytes, Vec<u8>);


#[derive(Clone, Serialize, Deserialize, Debug)]
pub enum RelayedMessageRequest {
    Http(AgnosticRequest),
    Log(ZephyrLog)
}