xrpl_std/core/
error_codes.rs

1use crate::host::Error::{InternalError, OutOfBounds};
2use crate::host::trace::trace_num;
3use crate::host::{Error, Result, Result::Err, Result::Ok};
4
5// TODO: Translate these into the Error enum (see host/mod.rs) or else move that enum into here?
6// TODO: Consider renaming this to errors.
7pub const INTERNAL_ERROR: i32 = -1;
8pub const FIELD_NOT_FOUND: i32 = -2;
9pub const BUFFER_TOO_SMALL: i32 = -3;
10pub const NO_ARRAY: i32 = -4;
11pub const NOT_LEAF_FIELD: i32 = -5;
12pub const LOCATOR_MALFORMED: i32 = -6;
13pub const SLOT_OUT_RANGE: i32 = -7;
14pub const NO_FREE_SLOTS: i32 = -8;
15pub const INVALID_SLOT: i32 = -9;
16pub const LEDGER_OBJ_NOT_FOUND: i32 = -10;
17pub const DECODING_ERROR: i32 = -11;
18pub const DATA_FIELD_TOO_LARGE: i32 = -12;
19pub const POINTER_OUT_OF_BOUNDS: i32 = -13;
20pub const NO_MEM_EXPORTED: i32 = -14;
21pub const INVALID_PARAMS: i32 = -15;
22pub const INVALID_ACCOUNT: i32 = -16;
23pub const INVALID_FIELD: i32 = -17;
24pub const INDEX_OUT_OF_BOUNDS: i32 = -18;
25
26/// Evaluates a result code and executes a closure on success (result_code > 0).
27///
28/// # Arguments
29///
30/// * `result_code` - An integer representing the operation result code
31/// * `on_success` - A closure that will be executed if result_code > 0
32///
33/// # Type Parameters
34///
35/// * `F` - The type of the closure
36/// * `T` - The return type of the closure
37///
38/// # Returns
39///
40/// Returns a `Result<T>` where:
41/// * `Ok(T)` - Contains the value returned by the closure if result_code > 0
42/// * `Ok(None)` - If result_code == 0 (no data/empty result)
43/// * `Err(Error)` - For negative result codes
44///
45/// # Note
46///
47/// This function treats 0 as a valid "no data" state and positive values as success.
48#[inline(always)]
49pub fn match_result_code<F, T>(result_code: i32, on_success: F) -> Result<T>
50where
51    F: FnOnce() -> T,
52{
53    match result_code {
54        code if code >= 0 => Ok(on_success()),
55        code => Err(Error::from_code(code)),
56    }
57}
58
59#[inline(always)]
60pub fn match_result_code_optional<F, T>(result_code: i32, on_success: F) -> Result<Option<T>>
61where
62    F: FnOnce() -> Option<T>,
63{
64    match result_code {
65        code if code >= 0 => Ok(on_success()),
66        code => Err(Error::from_code(code)),
67    }
68}
69
70/// Evaluates a result code against an expected number of bytes and executes a closure on exact match.
71///
72/// # Arguments
73///
74/// * `result_code` - An integer representing the operation result code
75/// * `expected_num_bytes` - The exact number of bytes expected to have been written
76/// * `on_success` - A closure that will be executed if the result code matches expected bytes
77///
78/// # Type Parameters
79///
80/// * `F` - The type of the closure
81/// * `T` - The return type of the closure
82///
83/// # Returns
84///
85/// Returns a `Result<T>` where:
86/// * `Ok(T)` - Contains the value returned by the closure if result_code matches expected_num_bytes
87/// * `Err(InternalError)` - If result_code is non-negative but doesn't match expected bytes
88/// * `Err(Error)` - For negative result codes
89///
90/// # Note
91///
92/// This function requires an exact match between the result code and expected byte count,
93/// making it suitable for operations where the exact amount of data written is critical.
94#[inline]
95pub fn match_result_code_with_expected_bytes<F, T>(
96    result_code: i32,
97    expected_num_bytes: usize,
98    on_success: F,
99) -> Result<T>
100where
101    F: FnOnce() -> T,
102{
103    match result_code {
104        code if code as usize == expected_num_bytes => Ok(on_success()),
105        code if code >= 0 => Err(InternalError), // If here, this is a bug
106        code => Err(Error::from_code(code)),
107    }
108}
109
110#[inline]
111pub fn match_result_code_with_expected_bytes_optional<F, T>(
112    result_code: i32,
113    expected_num_bytes: usize,
114    on_success: F,
115) -> Result<Option<T>>
116where
117    F: FnOnce() -> Option<T>,
118{
119    match result_code {
120        code if code as usize == expected_num_bytes => Ok(on_success()),
121        code if code == FIELD_NOT_FOUND => Ok(None),
122        // Handle all positive, unexpected values as an internal error.
123        code if code >= 0 => {
124            let _ = trace_num(
125                "Byte array was expected to have this many bytes: ",
126                expected_num_bytes as i64,
127            );
128            let _ = trace_num("Byte array had this many bytes: ", code as i64);
129            Err(OutOfBounds)
130        }
131        // Handle all error values overtly.
132        code => {
133            let _ = trace_num("Encountered error_code:", code as i64);
134            Err(Error::from_code(code))
135        }
136    }
137}