-
Notifications
You must be signed in to change notification settings - Fork 1.4k
/
Copy pathdecode.rs
158 lines (146 loc) · 4.78 KB
/
decode.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
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
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
//! Provides [`Decode`] for decoding values from the database.
use std::borrow::Cow;
use std::rc::Rc;
use std::sync::Arc;
use crate::database::Database;
use crate::error::BoxDynError;
use crate::value::ValueRef;
/// A type that can be decoded from the database.
///
/// ## How can I implement `Decode`?
///
/// A manual implementation of `Decode` can be useful when adding support for
/// types externally to SQLx.
///
/// The following showcases how to implement `Decode` to be generic over [`Database`]. The
/// implementation can be marginally simpler if you remove the `DB` type parameter and explicitly
/// use the concrete [`ValueRef`](Database::ValueRef) and [`TypeInfo`](Database::TypeInfo) types.
///
/// ```rust
/// # use sqlx_core::database::{Database};
/// # use sqlx_core::decode::Decode;
/// # use sqlx_core::types::Type;
/// # use std::error::Error;
/// #
/// struct MyType;
///
/// # impl<DB: Database> Type<DB> for MyType {
/// # fn type_info() -> DB::TypeInfo { todo!() }
/// # }
/// #
/// # impl std::str::FromStr for MyType {
/// # type Err = sqlx_core::error::Error;
/// # fn from_str(s: &str) -> Result<Self, Self::Err> { todo!() }
/// # }
/// #
/// // DB is the database driver
/// // `'r` is the lifetime of the `Row` being decoded
/// impl<'r, DB: Database> Decode<'r, DB> for MyType
/// where
/// // we want to delegate some of the work to string decoding so let's make sure strings
/// // are supported by the database
/// &'r str: Decode<'r, DB>
/// {
/// fn decode(
/// value: <DB as Database>::ValueRef<'r>,
/// ) -> Result<MyType, Box<dyn Error + 'static + Send + Sync>> {
/// // the interface of ValueRef is largely unstable at the moment
/// // so this is not directly implementable
///
/// // however, you can delegate to a type that matches the format of the type you want
/// // to decode (such as a UTF-8 string)
///
/// let value = <&str as Decode<DB>>::decode(value)?;
///
/// // now you can parse this into your type (assuming there is a `FromStr`)
///
/// Ok(value.parse()?)
/// }
/// }
/// ```
pub trait Decode<'r, DB: Database>: Sized {
/// Decode a new value of this type using a raw value from the database.
fn decode(value: <DB as Database>::ValueRef<'r>) -> Result<Self, BoxDynError>;
}
// implement `Decode` for Option<T> for all SQL types
impl<'r, DB, T> Decode<'r, DB> for Option<T>
where
DB: Database,
T: Decode<'r, DB>,
{
fn decode(value: <DB as Database>::ValueRef<'r>) -> Result<Self, BoxDynError> {
if value.is_null() {
Ok(None)
} else {
Ok(Some(T::decode(value)?))
}
}
}
macro_rules! impl_decode_for_smartpointer {
($smart_pointer:tt) => {
impl<'r, DB, T> Decode<'r, DB> for $smart_pointer<T>
where
DB: Database,
T: Decode<'r, DB>,
{
fn decode(value: <DB as Database>::ValueRef<'r>) -> Result<Self, BoxDynError> {
Ok(Self::new(T::decode(value)?))
}
}
impl<'r, DB> Decode<'r, DB> for $smart_pointer<str>
where
DB: Database,
&'r str: Decode<'r, DB>,
{
fn decode(value: <DB as Database>::ValueRef<'r>) -> Result<Self, BoxDynError> {
let ref_str = <&str as Decode<DB>>::decode(value)?;
Ok(ref_str.into())
}
}
impl<'r, DB> Decode<'r, DB> for $smart_pointer<[u8]>
where
DB: Database,
&'r [u8]: Decode<'r, DB>,
{
fn decode(value: <DB as Database>::ValueRef<'r>) -> Result<Self, BoxDynError> {
let ref_str = <&[u8] as Decode<DB>>::decode(value)?;
Ok(ref_str.into())
}
}
};
}
impl_decode_for_smartpointer!(Arc);
impl_decode_for_smartpointer!(Box);
impl_decode_for_smartpointer!(Rc);
// implement `Decode` for Cow<T> for all SQL types
impl<'r, DB, T> Decode<'r, DB> for Cow<'_, T>
where
DB: Database,
T: ToOwned,
<T as ToOwned>::Owned: Decode<'r, DB>,
{
fn decode(value: <DB as Database>::ValueRef<'r>) -> Result<Self, BoxDynError> {
let owned = <<T as ToOwned>::Owned as Decode<DB>>::decode(value)?;
Ok(Cow::Owned(owned))
}
}
impl<'r, DB> Decode<'r, DB> for Cow<'r, str>
where
DB: Database,
&'r str: Decode<'r, DB>,
{
fn decode(value: <DB as Database>::ValueRef<'r>) -> Result<Self, BoxDynError> {
let borrowed = <&str as Decode<DB>>::decode(value)?;
Ok(Cow::Borrowed(borrowed))
}
}
impl<'r, DB> Decode<'r, DB> for Cow<'r, [u8]>
where
DB: Database,
&'r [u8]: Decode<'r, DB>,
{
fn decode(value: <DB as Database>::ValueRef<'r>) -> Result<Self, BoxDynError> {
let borrowed = <&[u8] as Decode<DB>>::decode(value)?;
Ok(Cow::Borrowed(borrowed))
}
}