alloy_primitives/
sqlx.rs

1//! Support for the [`sqlx`](https://crates.io/crates/sqlx) crate.
2//!
3//! Supports big-endian binary serialization via sqlx binary types (e.g., BINARY(N), BYTEA, BLOB).
4//! Similar to [`ruint`'s implementation](https://github.com/recmo/uint/blob/main/src/support/sqlx.rs)
5
6#![cfg_attr(docsrs, doc(cfg(feature = "sqlx")))]
7
8use alloc::{boxed::Box, vec::Vec};
9
10use ruint::support::sqlx::DecodeError;
11use sqlx_core::{
12    database::Database,
13    decode::Decode,
14    encode::{Encode, IsNull},
15    error::BoxDynError,
16    types::Type,
17};
18
19use crate::{Bytes, FixedBytes, Signed};
20
21impl<const BYTES: usize, DB> Type<DB> for FixedBytes<BYTES>
22where
23    DB: Database,
24    Vec<u8>: Type<DB>,
25{
26    fn type_info() -> DB::TypeInfo {
27        <Vec<u8> as Type<DB>>::type_info()
28    }
29
30    fn compatible(ty: &DB::TypeInfo) -> bool {
31        <Vec<u8> as Type<DB>>::compatible(ty)
32    }
33}
34
35impl<'a, const BYTES: usize, DB> Encode<'a, DB> for FixedBytes<BYTES>
36where
37    DB: Database,
38    Vec<u8>: Encode<'a, DB>,
39{
40    fn encode_by_ref(
41        &self,
42        buf: &mut <DB as Database>::ArgumentBuffer<'a>,
43    ) -> Result<IsNull, BoxDynError> {
44        self.as_slice().to_vec().encode_by_ref(buf)
45    }
46}
47
48impl<'a, const BYTES: usize, DB> Decode<'a, DB> for FixedBytes<BYTES>
49where
50    DB: Database,
51    Vec<u8>: Decode<'a, DB>,
52{
53    fn decode(value: <DB as Database>::ValueRef<'a>) -> Result<Self, BoxDynError> {
54        let bytes = Vec::<u8>::decode(value)?;
55        Self::try_from(bytes.as_slice()).map_err(|e| Box::new(e) as BoxDynError)
56    }
57}
58
59impl<const BITS: usize, const LIMBS: usize, DB: Database> Type<DB> for Signed<BITS, LIMBS>
60where
61    Vec<u8>: Type<DB>,
62{
63    fn type_info() -> DB::TypeInfo {
64        <Vec<u8> as Type<DB>>::type_info()
65    }
66
67    fn compatible(ty: &DB::TypeInfo) -> bool {
68        <Vec<u8> as Type<DB>>::compatible(ty)
69    }
70}
71
72impl<'a, const BITS: usize, const LIMBS: usize, DB: Database> Encode<'a, DB> for Signed<BITS, LIMBS>
73where
74    Vec<u8>: Encode<'a, DB>,
75{
76    fn encode_by_ref(
77        &self,
78        buf: &mut <DB as Database>::ArgumentBuffer<'a>,
79    ) -> Result<IsNull, BoxDynError> {
80        self.0.to_be_bytes_vec().encode_by_ref(buf)
81    }
82}
83
84impl<'a, const BITS: usize, const LIMBS: usize, DB: Database> Decode<'a, DB> for Signed<BITS, LIMBS>
85where
86    Vec<u8>: Decode<'a, DB>,
87{
88    fn decode(value: <DB as Database>::ValueRef<'a>) -> Result<Self, BoxDynError> {
89        let bytes = Vec::<u8>::decode(value)?;
90        Self::try_from_be_slice(bytes.as_slice()).ok_or_else(|| DecodeError::Overflow.into())
91    }
92}
93
94impl<DB: Database> Type<DB> for Bytes
95where
96    Vec<u8>: Type<DB>,
97{
98    fn type_info() -> DB::TypeInfo {
99        <Vec<u8> as Type<DB>>::type_info()
100    }
101
102    fn compatible(ty: &DB::TypeInfo) -> bool {
103        <Vec<u8> as Type<DB>>::compatible(ty)
104    }
105}
106
107impl<'a, DB: Database> Encode<'a, DB> for Bytes
108where
109    Vec<u8>: Encode<'a, DB>,
110{
111    fn encode_by_ref(
112        &self,
113        buf: &mut <DB as Database>::ArgumentBuffer<'a>,
114    ) -> Result<IsNull, BoxDynError> {
115        self.to_vec().encode_by_ref(buf)
116    }
117}
118
119impl<'a, DB: Database> Decode<'a, DB> for Bytes
120where
121    Vec<u8>: Decode<'a, DB>,
122{
123    fn decode(value: <DB as Database>::ValueRef<'a>) -> Result<Self, BoxDynError> {
124        Vec::<u8>::decode(value).map(Self::from)
125    }
126}