diesel/pg/
value.rs

1use std::num::NonZeroU32;
2use std::ops::Range;
3
4/// Raw postgres value as received from the database
5#[derive(Clone, Copy)]
6#[allow(missing_debug_implementations)]
7#[cfg(feature = "postgres_backend")]
8pub struct PgValue<'a> {
9    raw_value: &'a [u8],
10    type_oid_lookup: &'a dyn TypeOidLookup,
11}
12
13/// This is a helper trait to defer a type oid
14/// lookup to a later point in time
15///
16/// This is mainly used in the `PgConnection`
17/// implementation so that we do not need to call
18/// into libpq if we do not need the type oid.
19///
20/// Backend implementations based on pure rustc
21/// database connection crates can likely reuse
22/// the implementation for `NonZeroU32` here instead
23/// of providing their own custom implementation
24#[cfg_attr(
25    docsrs,
26    doc(cfg(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"))
27)]
28#[allow(unreachable_pub)]
29pub trait TypeOidLookup {
30    /// Lookup the type oid for the current value
31    fn lookup(&self) -> NonZeroU32;
32}
33
34impl<F> TypeOidLookup for F
35where
36    F: Fn() -> NonZeroU32,
37{
38    fn lookup(&self) -> NonZeroU32 {
39        (self)()
40    }
41}
42
43impl TypeOidLookup for PgValue<'_> {
44    fn lookup(&self) -> NonZeroU32 {
45        self.type_oid_lookup.lookup()
46    }
47}
48
49impl TypeOidLookup for NonZeroU32 {
50    fn lookup(&self) -> NonZeroU32 {
51        *self
52    }
53}
54
55impl<'a> PgValue<'a> {
56    #[cfg(test)]
57    pub(crate) fn for_test(raw_value: &'a [u8]) -> Self {
58        #[allow(unsafe_code)] // that's actual safe
59        static FAKE_OID: NonZeroU32 = unsafe {
60            // 42 != 0, so this is actually safe
61            NonZeroU32::new_unchecked(42)
62        };
63        Self {
64            raw_value,
65            type_oid_lookup: &FAKE_OID,
66        }
67    }
68
69    /// Create a new instance of `PgValue` based on a byte buffer
70    /// and a way to receive information about the type of the value
71    /// represented by the buffer
72    #[cfg(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes")]
73    pub fn new(raw_value: &'a [u8], type_oid_lookup: &'a dyn TypeOidLookup) -> Self {
74        Self::new_internal(raw_value, type_oid_lookup)
75    }
76
77    pub(in crate::pg) fn new_internal(
78        raw_value: &'a [u8],
79        type_oid_lookup: &'a dyn TypeOidLookup,
80    ) -> Self {
81        Self {
82            raw_value,
83            type_oid_lookup,
84        }
85    }
86
87    /// Get the underlying raw byte representation
88    pub fn as_bytes(&self) -> &[u8] {
89        self.raw_value
90    }
91
92    /// Get the type oid of this value
93    pub fn get_oid(&self) -> NonZeroU32 {
94        self.type_oid_lookup.lookup()
95    }
96
97    pub(crate) fn subslice(&self, range: Range<usize>) -> Self {
98        Self {
99            raw_value: &self.raw_value[range],
100            ..*self
101        }
102    }
103}