Skip to main content

postgres_types/
lib.rs

1//! Conversions to and from Postgres types.
2//!
3//! This crate is used by the `tokio-postgres` and `postgres` crates. You normally don't need to depend directly on it
4//! unless you want to define your own `ToSql` or `FromSql` definitions.
5//!
6//! # Derive
7//!
8//! If the `derive` cargo feature is enabled, you can derive `ToSql` and `FromSql` implementations for custom Postgres
9//! types. Explicitly, modify your `Cargo.toml` file to include the following:
10//!
11//! ```toml
12//! [dependencies]
13//! postgres-types = { version = "0.X.X", features = ["derive"] }
14//! ```
15//!
16//! ## Enums
17//!
18//! Postgres enums correspond to C-like enums in Rust:
19//!
20//! ```sql
21//! CREATE TYPE "Mood" AS ENUM (
22//!     'Sad',
23//!     'Ok',
24//!     'Happy'
25//! );
26//! ```
27//!
28//! ```rust
29//! # #[cfg(feature = "derive")]
30//! use postgres_types::{ToSql, FromSql};
31//!
32//! # #[cfg(feature = "derive")]
33//! #[derive(Debug, ToSql, FromSql)]
34//! enum Mood {
35//!     Sad,
36//!     Ok,
37//!     Happy,
38//! }
39//! ```
40//!
41//! ## Domains
42//!
43//! Postgres domains correspond to tuple structs with one member in Rust:
44//!
45//! ```sql
46//! CREATE DOMAIN "SessionId" AS BYTEA CHECK(octet_length(VALUE) = 16);
47//! ```
48//!
49//! ```rust
50//! # #[cfg(feature = "derive")]
51//! use postgres_types::{ToSql, FromSql};
52//!
53//! # #[cfg(feature = "derive")]
54//! #[derive(Debug, ToSql, FromSql)]
55//! struct SessionId(Vec<u8>);
56//! ```
57//!
58//! ## Newtypes
59//!
60//! The `#[postgres(transparent)]` attribute can be used on a single-field tuple struct to create a
61//! Rust-only wrapper type that will use the [`ToSql`] & [`FromSql`] implementation of the inner
62//! value :
63//! ```rust
64//! # #[cfg(feature = "derive")]
65//! use postgres_types::{ToSql, FromSql};
66//!
67//! # #[cfg(feature = "derive")]
68//! #[derive(Debug, ToSql, FromSql)]
69//! #[postgres(transparent)]
70//! struct UserId(i32);
71//! ```
72//!
73//! ## Composites
74//!
75//! Postgres composite types correspond to structs in Rust:
76//!
77//! ```sql
78//! CREATE TYPE "InventoryItem" AS (
79//!     name TEXT,
80//!     supplier_id INT,
81//!     price DOUBLE PRECISION
82//! );
83//! ```
84//!
85//! ```rust
86//! # #[cfg(feature = "derive")]
87//! use postgres_types::{ToSql, FromSql};
88//!
89//! # #[cfg(feature = "derive")]
90//! #[derive(Debug, ToSql, FromSql)]
91//! struct InventoryItem {
92//!     name: String,
93//!     supplier_id: i32,
94//!     price: Option<f64>,
95//! }
96//! ```
97//!
98//! ## Naming
99//!
100//! The derived implementations will enforce exact matches of type, field, and variant names between the Rust and
101//! Postgres types. The `#[postgres(name = "...")]` attribute can be used to adjust the name on a type, variant, or
102//! field:
103//!
104//! ```sql
105//! CREATE TYPE mood AS ENUM (
106//!     'sad',
107//!     'ok',
108//!     'happy'
109//! );
110//! ```
111//!
112//! ```rust
113//! # #[cfg(feature = "derive")]
114//! use postgres_types::{ToSql, FromSql};
115//!
116//! # #[cfg(feature = "derive")]
117//! #[derive(Debug, ToSql, FromSql)]
118//! #[postgres(name = "mood")]
119//! enum Mood {
120//!     #[postgres(name = "sad")]
121//!     Sad,
122//!     #[postgres(name = "ok")]
123//!     Ok,
124//!     #[postgres(name = "happy")]
125//!     Happy,
126//! }
127//! ```
128//!
129//! Alternatively, the `#[postgres(rename_all = "...")]` attribute can be used to rename all fields or variants
130//! with the chosen casing convention. This will not affect the struct or enum's type name. Note that
131//! `#[postgres(name = "...")]` takes precendence when used in conjunction with `#[postgres(rename_all = "...")]`:
132//!
133//! ```rust
134//! # #[cfg(feature = "derive")]
135//! use postgres_types::{ToSql, FromSql};
136//!
137//! # #[cfg(feature = "derive")]
138//! #[derive(Debug, ToSql, FromSql)]
139//! #[postgres(name = "mood", rename_all = "snake_case")]
140//! enum Mood {
141//!     #[postgres(name = "ok")]
142//!     Ok,             // ok
143//!     VeryHappy,      // very_happy
144//! }
145//! ```
146//!
147//! The following case conventions are supported:
148//! - `"lowercase"`
149//! - `"UPPERCASE"`
150//! - `"PascalCase"`
151//! - `"camelCase"`
152//! - `"snake_case"`
153//! - `"SCREAMING_SNAKE_CASE"`
154//! - `"kebab-case"`
155//! - `"SCREAMING-KEBAB-CASE"`
156//! - `"Train-Case"`
157//!
158//! ## Allowing Enum Mismatches
159//!
160//! By default the generated implementation of [`ToSql`] & [`FromSql`] for enums will require an exact match of the enum
161//! variants between the Rust and Postgres types.
162//! To allow mismatches, the `#[postgres(allow_mismatch)]` attribute can be used on the enum definition:
163//!
164//! ```sql
165//! CREATE TYPE mood AS ENUM (
166//!   'Sad',
167//!   'Ok',
168//!   'Happy'
169//! );
170//! ```
171//!
172//! ```rust
173//! # #[cfg(feature = "derive")]
174//! use postgres_types::{ToSql, FromSql};
175//!
176//! # #[cfg(feature = "derive")]
177//! #[derive(Debug, ToSql, FromSql)]
178//! #[postgres(allow_mismatch)]
179//! enum Mood {
180//!    Happy,
181//!    Meh,
182//! }
183//! ```
184#![warn(clippy::all, rust_2018_idioms, missing_docs)]
185use fallible_iterator::FallibleIterator;
186use postgres_protocol::types::{self, ArrayDimension};
187use std::any::type_name;
188use std::borrow::Cow;
189use std::collections::HashMap;
190use std::error::Error;
191use std::fmt;
192use std::hash::BuildHasher;
193use std::net::IpAddr;
194use std::sync::Arc;
195use std::time::{Duration, SystemTime, UNIX_EPOCH};
196
197#[cfg(feature = "derive")]
198pub use postgres_derive::{FromSql, ToSql};
199
200#[cfg(feature = "with-serde_json-1")]
201pub use crate::serde_json_1::Json;
202use crate::type_gen::{Inner, Other};
203
204#[doc(inline)]
205pub use postgres_protocol::Oid;
206
207#[doc(inline)]
208pub use pg_lsn::PgLsn;
209
210pub use crate::special::{Date, Timestamp};
211use bytes::BytesMut;
212
213// Number of seconds from 1970-01-01 to 2000-01-01
214const TIME_SEC_CONVERSION: u64 = 946_684_800;
215const USEC_PER_SEC: u64 = 1_000_000;
216const NSEC_PER_USEC: u64 = 1_000;
217
218/// Generates a simple implementation of `ToSql::accepts` which accepts the
219/// types passed to it.
220#[macro_export]
221macro_rules! accepts {
222    ($($expected:ident),+) => (
223        fn accepts(ty: &$crate::Type) -> bool {
224            matches!(*ty, $($crate::Type::$expected)|+)
225        }
226    )
227}
228
229/// Generates an implementation of `ToSql::to_sql_checked`.
230///
231/// All `ToSql` implementations should use this macro.
232#[macro_export]
233macro_rules! to_sql_checked {
234    () => {
235        fn to_sql_checked(
236            &self,
237            ty: &$crate::Type,
238            out: &mut $crate::private::BytesMut,
239        ) -> ::std::result::Result<
240            $crate::IsNull,
241            Box<dyn ::std::error::Error + ::std::marker::Sync + ::std::marker::Send>,
242        > {
243            $crate::__to_sql_checked(self, ty, out)
244        }
245    };
246}
247
248// WARNING: this function is not considered part of this crate's public API.
249// It is subject to change at any time.
250#[doc(hidden)]
251pub fn __to_sql_checked<T>(
252    v: &T,
253    ty: &Type,
254    out: &mut BytesMut,
255) -> Result<IsNull, Box<dyn Error + Sync + Send>>
256where
257    T: ToSql,
258{
259    if !T::accepts(ty) {
260        return Err(Box::new(WrongType::new::<T>(ty.clone())));
261    }
262    v.to_sql(ty, out)
263}
264
265#[cfg(feature = "with-bit-vec-0_6")]
266mod bit_vec_06;
267#[cfg(feature = "with-bit-vec-0_7")]
268mod bit_vec_07;
269#[cfg(feature = "with-bit-vec-0_8")]
270mod bit_vec_08;
271#[cfg(feature = "with-bit-vec-0_9")]
272mod bit_vec_09;
273#[cfg(feature = "with-chrono-0_4")]
274mod chrono_04;
275#[cfg(feature = "with-cidr-0_2")]
276mod cidr_02;
277#[cfg(feature = "with-cidr-0_3")]
278mod cidr_03;
279#[cfg(feature = "with-eui48-0_4")]
280mod eui48_04;
281#[cfg(feature = "with-eui48-1")]
282mod eui48_1;
283#[cfg(feature = "with-geo-types-0_6")]
284mod geo_types_06;
285#[cfg(feature = "with-geo-types-0_7")]
286mod geo_types_07;
287#[cfg(feature = "with-jiff-0_1")]
288mod jiff_01;
289#[cfg(feature = "with-jiff-0_2")]
290mod jiff_02;
291#[cfg(feature = "with-serde_json-1")]
292mod serde_json_1;
293#[cfg(feature = "with-smol_str-01")]
294mod smol_str_01;
295#[cfg(feature = "with-time-0_2")]
296mod time_02;
297#[cfg(feature = "with-time-0_3")]
298mod time_03;
299#[cfg(feature = "with-uuid-0_8")]
300mod uuid_08;
301#[cfg(feature = "with-uuid-1")]
302mod uuid_1;
303
304// The time::{date, time} macros produce compile errors if the crate package is renamed.
305#[cfg(feature = "with-time-0_2")]
306extern crate time_02 as time;
307
308mod pg_lsn;
309#[doc(hidden)]
310pub mod private;
311mod special;
312mod type_gen;
313
314/// A Postgres type.
315#[derive(PartialEq, Eq, Clone, Hash)]
316pub struct Type(Inner);
317
318impl fmt::Debug for Type {
319    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
320        fmt::Debug::fmt(&self.0, fmt)
321    }
322}
323
324impl fmt::Display for Type {
325    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
326        match self.schema() {
327            "public" | "pg_catalog" => {}
328            schema => write!(fmt, "{schema}.")?,
329        }
330        fmt.write_str(self.name())
331    }
332}
333
334impl Type {
335    /// Creates a new `Type`.
336    pub fn new(name: String, oid: Oid, kind: Kind, schema: String) -> Type {
337        Type(Inner::Other(Arc::new(Other {
338            name,
339            oid,
340            kind,
341            schema,
342        })))
343    }
344
345    /// Returns the `Type` corresponding to the provided `Oid` if it
346    /// corresponds to a built-in type.
347    pub fn from_oid(oid: Oid) -> Option<Type> {
348        Inner::from_oid(oid).map(Type)
349    }
350
351    /// Returns the OID of the `Type`.
352    pub fn oid(&self) -> Oid {
353        self.0.oid()
354    }
355
356    /// Returns the kind of this type.
357    pub fn kind(&self) -> &Kind {
358        self.0.kind()
359    }
360
361    /// Returns the schema of this type.
362    pub fn schema(&self) -> &str {
363        match self.0 {
364            Inner::Other(ref u) => &u.schema,
365            _ => "pg_catalog",
366        }
367    }
368
369    /// Returns the name of this type.
370    pub fn name(&self) -> &str {
371        self.0.name()
372    }
373}
374
375/// Represents the kind of a Postgres type.
376#[derive(Debug, Clone, PartialEq, Eq, Hash)]
377#[non_exhaustive]
378pub enum Kind {
379    /// A simple type like `VARCHAR` or `INTEGER`.
380    Simple,
381    /// An enumerated type along with its variants.
382    Enum(Vec<String>),
383    /// A pseudo-type.
384    Pseudo,
385    /// An array type along with the type of its elements.
386    Array(Type),
387    /// A range type along with the type of its elements.
388    Range(Type),
389    /// A multirange type along with the type of its elements.
390    Multirange(Type),
391    /// A domain type along with its underlying type.
392    Domain(Type),
393    /// A composite type along with information about its fields.
394    Composite(Vec<Field>),
395}
396
397/// Information about a field of a composite type.
398#[derive(Debug, Clone, PartialEq, Eq, Hash)]
399pub struct Field {
400    name: String,
401    type_: Type,
402}
403
404impl Field {
405    /// Creates a new `Field`.
406    pub fn new(name: String, type_: Type) -> Field {
407        Field { name, type_ }
408    }
409
410    /// Returns the name of the field.
411    pub fn name(&self) -> &str {
412        &self.name
413    }
414
415    /// Returns the type of the field.
416    pub fn type_(&self) -> &Type {
417        &self.type_
418    }
419}
420
421/// An error indicating that a `NULL` Postgres value was passed to a `FromSql`
422/// implementation that does not support `NULL` values.
423#[derive(Debug, Clone, Copy)]
424pub struct WasNull;
425
426impl fmt::Display for WasNull {
427    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
428        fmt.write_str("a Postgres value was `NULL`")
429    }
430}
431
432impl Error for WasNull {}
433
434/// An error indicating that a conversion was attempted between incompatible
435/// Rust and Postgres types.
436#[derive(Debug)]
437pub struct WrongType {
438    postgres: Type,
439    rust: &'static str,
440}
441
442impl fmt::Display for WrongType {
443    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
444        write!(
445            fmt,
446            "cannot convert between the Rust type `{}` and the Postgres type `{}`",
447            self.rust, self.postgres,
448        )
449    }
450}
451
452impl Error for WrongType {}
453
454impl WrongType {
455    /// Creates a new `WrongType` error.
456    pub fn new<T>(ty: Type) -> WrongType {
457        WrongType {
458            postgres: ty,
459            rust: type_name::<T>(),
460        }
461    }
462}
463
464/// A trait for types that can be created from a Postgres value.
465///
466/// # Types
467///
468/// The following implementations are provided by this crate, along with the
469/// corresponding Postgres types:
470///
471/// | Rust type                         | Postgres type(s)                              |
472/// |-----------------------------------|-----------------------------------------------|
473/// | `bool`                            | BOOL                                          |
474/// | `i8`                              | "char"                                        |
475/// | `i16`                             | SMALLINT, SMALLSERIAL                         |
476/// | `i32`                             | INT, SERIAL                                   |
477/// | `u32`                             | OID                                           |
478/// | `i64`                             | BIGINT, BIGSERIAL                             |
479/// | `f32`                             | REAL                                          |
480/// | `f64`                             | DOUBLE PRECISION                              |
481/// | `&str`/`String`                   | VARCHAR, CHAR(n), TEXT, CITEXT, NAME, UNKNOWN |
482/// |                                   | LTREE, LQUERY, LTXTQUERY                      |
483/// | `&[u8]`/`Vec<u8>`                 | BYTEA                                         |
484/// | `HashMap<String, Option<String>>` | HSTORE                                        |
485/// | `SystemTime`                      | TIMESTAMP, TIMESTAMP WITH TIME ZONE           |
486/// | `IpAddr`                          | INET                                          |
487///
488/// In addition, some implementations are provided for types in third party
489/// crates. These are disabled by default; to opt into one of these
490/// implementations, activate the Cargo feature corresponding to the crate's
491/// name prefixed by `with-`. For example, the `with-serde_json-1` feature enables
492/// the implementation for the `serde_json::Value` type.
493///
494/// | Rust type                       | Postgres type(s)                    |
495/// |---------------------------------|-------------------------------------|
496/// | `chrono::NaiveDateTime`         | TIMESTAMP                           |
497/// | `chrono::DateTime<Utc>`         | TIMESTAMP WITH TIME ZONE            |
498/// | `chrono::DateTime<Local>`       | TIMESTAMP WITH TIME ZONE            |
499/// | `chrono::DateTime<FixedOffset>` | TIMESTAMP WITH TIME ZONE            |
500/// | `chrono::NaiveDate`             | DATE                                |
501/// | `chrono::NaiveTime`             | TIME                                |
502/// | `cidr::IpCidr`                  | CIDR                                |
503/// | `cidr::IpInet`                  | INET                                |
504/// | `time::PrimitiveDateTime`       | TIMESTAMP                           |
505/// | `time::OffsetDateTime`          | TIMESTAMP WITH TIME ZONE            |
506/// | `time::Date`                    | DATE                                |
507/// | `time::Time`                    | TIME                                |
508/// | `jiff::civil::Date`             | DATE                                |
509/// | `jiff::civil::DateTime`         | TIMESTAMP                           |
510/// | `jiff::civil::Time`             | TIME                                |
511/// | `jiff::Timestamp`               | TIMESTAMP WITH TIME ZONE            |
512/// | `eui48::MacAddress`             | MACADDR                             |
513/// | `geo_types::Point<f64>`         | POINT                               |
514/// | `geo_types::Rect<f64>`          | BOX                                 |
515/// | `geo_types::LineString<f64>`    | PATH                                |
516/// | `serde_json::Value`             | JSON, JSONB                         |
517/// | `uuid::Uuid`                    | UUID                                |
518/// | `bit_vec::BitVec`               | BIT, VARBIT                         |
519/// | `eui48::MacAddress`             | MACADDR                             |
520/// | `cidr::InetCidr`                | CIDR                                |
521/// | `cidr::InetAddr`                | INET                                |
522/// | `smol_str::SmolStr`             | VARCHAR, CHAR(n), TEXT, CITEXT,     |
523/// |                                 | NAME, UNKNOWN, LTREE, LQUERY,       |
524/// |                                 | LTXTQUERY                           |
525///
526/// # Nullability
527///
528/// In addition to the types listed above, `FromSql` is implemented for
529/// `Option<T>` where `T` implements `FromSql`. An `Option<T>` represents a
530/// nullable Postgres value.
531///
532/// # Arrays
533///
534/// `FromSql` is implemented for `Vec<T>`, `Box<[T]>` and `[T; N]` where `T`
535/// implements `FromSql`, and corresponds to one-dimensional Postgres arrays.
536///
537/// **Note:** the impl for arrays only exist when the Cargo feature `array-impls`
538/// is enabled.
539pub trait FromSql<'a>: Sized {
540    /// Creates a new value of this type from a buffer of data of the specified
541    /// Postgres `Type` in its binary format.
542    ///
543    /// The caller of this method is responsible for ensuring that this type
544    /// is compatible with the Postgres `Type`.
545    fn from_sql(ty: &Type, raw: &'a [u8]) -> Result<Self, Box<dyn Error + Sync + Send>>;
546
547    /// Creates a new value of this type from a `NULL` SQL value.
548    ///
549    /// The caller of this method is responsible for ensuring that this type
550    /// is compatible with the Postgres `Type`.
551    ///
552    /// The default implementation returns `Err(Box::new(WasNull))`.
553    #[allow(unused_variables)]
554    fn from_sql_null(ty: &Type) -> Result<Self, Box<dyn Error + Sync + Send>> {
555        Err(Box::new(WasNull))
556    }
557
558    /// A convenience function that delegates to `from_sql` and `from_sql_null` depending on the
559    /// value of `raw`.
560    fn from_sql_nullable(
561        ty: &Type,
562        raw: Option<&'a [u8]>,
563    ) -> Result<Self, Box<dyn Error + Sync + Send>> {
564        match raw {
565            Some(raw) => Self::from_sql(ty, raw),
566            None => Self::from_sql_null(ty),
567        }
568    }
569
570    /// Determines if a value of this type can be created from the specified
571    /// Postgres `Type`.
572    fn accepts(ty: &Type) -> bool;
573}
574
575/// A trait for types which can be created from a Postgres value without borrowing any data.
576///
577/// This is primarily useful for trait bounds on functions.
578pub trait FromSqlOwned: for<'a> FromSql<'a> {}
579
580impl<T> FromSqlOwned for T where T: for<'a> FromSql<'a> {}
581
582impl<'a, T: FromSql<'a>> FromSql<'a> for Option<T> {
583    fn from_sql(ty: &Type, raw: &'a [u8]) -> Result<Option<T>, Box<dyn Error + Sync + Send>> {
584        <T as FromSql>::from_sql(ty, raw).map(Some)
585    }
586
587    fn from_sql_null(_: &Type) -> Result<Option<T>, Box<dyn Error + Sync + Send>> {
588        Ok(None)
589    }
590
591    fn accepts(ty: &Type) -> bool {
592        <T as FromSql>::accepts(ty)
593    }
594}
595
596impl<'a, T: FromSql<'a>> FromSql<'a> for Vec<T> {
597    fn from_sql(ty: &Type, raw: &'a [u8]) -> Result<Vec<T>, Box<dyn Error + Sync + Send>> {
598        let member_type = match *ty.kind() {
599            Kind::Array(ref member) => member,
600            _ => panic!("expected array type"),
601        };
602
603        let array = types::array_from_sql(raw)?;
604        if array.dimensions().count()? > 1 {
605            return Err("array contains too many dimensions".into());
606        }
607
608        array
609            .values()
610            .map(|v| T::from_sql_nullable(member_type, v))
611            .collect()
612    }
613
614    fn accepts(ty: &Type) -> bool {
615        match *ty.kind() {
616            Kind::Array(ref inner) => T::accepts(inner),
617            _ => false,
618        }
619    }
620}
621
622#[cfg(feature = "array-impls")]
623impl<'a, T: FromSql<'a>, const N: usize> FromSql<'a> for [T; N] {
624    fn from_sql(ty: &Type, raw: &'a [u8]) -> Result<Self, Box<dyn Error + Sync + Send>> {
625        let member_type = match *ty.kind() {
626            Kind::Array(ref member) => member,
627            _ => panic!("expected array type"),
628        };
629
630        let array = types::array_from_sql(raw)?;
631        if array.dimensions().count()? > 1 {
632            return Err("array contains too many dimensions".into());
633        }
634
635        let mut values = array.values();
636        let out = array_init::try_array_init(|i| {
637            let v = values
638                .next()?
639                .ok_or_else(|| -> Box<dyn Error + Sync + Send> {
640                    format!("too few elements in array (expected {N}, got {i})").into()
641                })?;
642            T::from_sql_nullable(member_type, v)
643        })?;
644        if values.next()?.is_some() {
645            return Err(
646                format!("excess elements in array (expected {N}, got more than that)",).into(),
647            );
648        }
649
650        Ok(out)
651    }
652
653    fn accepts(ty: &Type) -> bool {
654        match *ty.kind() {
655            Kind::Array(ref inner) => T::accepts(inner),
656            _ => false,
657        }
658    }
659}
660
661impl<'a, T: FromSql<'a>> FromSql<'a> for Box<T> {
662    fn from_sql(ty: &Type, row: &'a [u8]) -> Result<Self, Box<dyn Error + Sync + Send>> {
663        T::from_sql(ty, row).map(Box::new)
664    }
665
666    fn accepts(ty: &Type) -> bool {
667        T::accepts(ty)
668    }
669}
670
671impl<'a, T: FromSql<'a>> FromSql<'a> for Box<[T]> {
672    fn from_sql(ty: &Type, raw: &'a [u8]) -> Result<Self, Box<dyn Error + Sync + Send>> {
673        Vec::<T>::from_sql(ty, raw).map(Vec::into_boxed_slice)
674    }
675
676    fn accepts(ty: &Type) -> bool {
677        Vec::<T>::accepts(ty)
678    }
679}
680
681impl<'a> FromSql<'a> for Vec<u8> {
682    fn from_sql(_: &Type, raw: &'a [u8]) -> Result<Vec<u8>, Box<dyn Error + Sync + Send>> {
683        Ok(types::bytea_from_sql(raw).to_owned())
684    }
685
686    accepts!(BYTEA);
687}
688
689impl<'a> FromSql<'a> for &'a [u8] {
690    fn from_sql(_: &Type, raw: &'a [u8]) -> Result<&'a [u8], Box<dyn Error + Sync + Send>> {
691        Ok(types::bytea_from_sql(raw))
692    }
693
694    accepts!(BYTEA);
695}
696
697impl<'a> FromSql<'a> for String {
698    fn from_sql(ty: &Type, raw: &'a [u8]) -> Result<String, Box<dyn Error + Sync + Send>> {
699        <&str as FromSql>::from_sql(ty, raw).map(ToString::to_string)
700    }
701
702    fn accepts(ty: &Type) -> bool {
703        <&str as FromSql>::accepts(ty)
704    }
705}
706
707impl<'a> FromSql<'a> for Box<str> {
708    fn from_sql(ty: &Type, raw: &'a [u8]) -> Result<Box<str>, Box<dyn Error + Sync + Send>> {
709        <&str as FromSql>::from_sql(ty, raw)
710            .map(ToString::to_string)
711            .map(String::into_boxed_str)
712    }
713
714    fn accepts(ty: &Type) -> bool {
715        <&str as FromSql>::accepts(ty)
716    }
717}
718
719impl<'a> FromSql<'a> for &'a str {
720    fn from_sql(ty: &Type, raw: &'a [u8]) -> Result<&'a str, Box<dyn Error + Sync + Send>> {
721        match *ty {
722            ref ty if ty.name() == "ltree" => types::ltree_from_sql(raw),
723            ref ty if ty.name() == "lquery" => types::lquery_from_sql(raw),
724            ref ty if ty.name() == "ltxtquery" => types::ltxtquery_from_sql(raw),
725            _ => types::text_from_sql(raw),
726        }
727    }
728
729    fn accepts(ty: &Type) -> bool {
730        match *ty {
731            Type::VARCHAR | Type::TEXT | Type::BPCHAR | Type::NAME | Type::UNKNOWN => true,
732            ref ty
733                if (ty.name() == "citext"
734                    || ty.name() == "ltree"
735                    || ty.name() == "lquery"
736                    || ty.name() == "ltxtquery") =>
737            {
738                true
739            }
740            _ => false,
741        }
742    }
743}
744
745impl<'a> FromSql<'a> for Cow<'a, str> {
746    fn from_sql(ty: &Type, raw: &'a [u8]) -> Result<Cow<'a, str>, Box<dyn Error + Sync + Send>> {
747        <&str as FromSql>::from_sql(ty, raw).map(Cow::Borrowed)
748    }
749
750    fn accepts(ty: &Type) -> bool {
751        <&str as FromSql>::accepts(ty)
752    }
753}
754
755macro_rules! simple_from {
756    ($t:ty, $f:ident, $($expected:ident),+) => {
757        impl<'a> FromSql<'a> for $t {
758            fn from_sql(_: &Type, raw: &'a [u8]) -> Result<$t, Box<dyn Error + Sync + Send>> {
759                types::$f(raw)
760            }
761
762            accepts!($($expected),+);
763        }
764    }
765}
766
767simple_from!(bool, bool_from_sql, BOOL);
768simple_from!(i8, char_from_sql, CHAR);
769simple_from!(i16, int2_from_sql, INT2);
770simple_from!(i32, int4_from_sql, INT4);
771simple_from!(u32, oid_from_sql, OID);
772simple_from!(i64, int8_from_sql, INT8);
773simple_from!(f32, float4_from_sql, FLOAT4);
774simple_from!(f64, float8_from_sql, FLOAT8);
775
776impl<'a, S> FromSql<'a> for HashMap<String, Option<String>, S>
777where
778    S: Default + BuildHasher,
779{
780    fn from_sql(
781        _: &Type,
782        raw: &'a [u8],
783    ) -> Result<HashMap<String, Option<String>, S>, Box<dyn Error + Sync + Send>> {
784        types::hstore_from_sql(raw)?
785            .map(|(k, v)| Ok((k.to_owned(), v.map(str::to_owned))))
786            .collect()
787    }
788
789    fn accepts(ty: &Type) -> bool {
790        ty.name() == "hstore"
791    }
792}
793
794impl<'a> FromSql<'a> for SystemTime {
795    fn from_sql(_: &Type, raw: &'a [u8]) -> Result<SystemTime, Box<dyn Error + Sync + Send>> {
796        let time = types::timestamp_from_sql(raw)?;
797        let epoch = UNIX_EPOCH + Duration::from_secs(TIME_SEC_CONVERSION);
798
799        let negative = time < 0;
800        let time = time.unsigned_abs();
801
802        let secs = time / USEC_PER_SEC;
803        let nsec = (time % USEC_PER_SEC) * NSEC_PER_USEC;
804        let offset = Duration::new(secs, nsec as u32);
805
806        let time = if negative {
807            epoch - offset
808        } else {
809            epoch + offset
810        };
811
812        Ok(time)
813    }
814
815    accepts!(TIMESTAMP, TIMESTAMPTZ);
816}
817
818impl<'a> FromSql<'a> for IpAddr {
819    fn from_sql(_: &Type, raw: &'a [u8]) -> Result<IpAddr, Box<dyn Error + Sync + Send>> {
820        let inet = types::inet_from_sql(raw)?;
821        Ok(inet.addr())
822    }
823
824    accepts!(INET);
825}
826
827/// An enum representing the nullability of a Postgres value.
828pub enum IsNull {
829    /// The value is NULL.
830    Yes,
831    /// The value is not NULL.
832    No,
833}
834
835/// A trait for types that can be converted into Postgres values.
836///
837/// # Types
838///
839/// The following implementations are provided by this crate, along with the
840/// corresponding Postgres types:
841///
842/// | Rust type                         | Postgres type(s)                     |
843/// |-----------------------------------|--------------------------------------|
844/// | `bool`                            | BOOL                                 |
845/// | `i8`                              | "char"                               |
846/// | `i16`                             | SMALLINT, SMALLSERIAL                |
847/// | `i32`                             | INT, SERIAL                          |
848/// | `u32`                             | OID                                  |
849/// | `i64`                             | BIGINT, BIGSERIAL                    |
850/// | `f32`                             | REAL                                 |
851/// | `f64`                             | DOUBLE PRECISION                     |
852/// | `&str`/`String`                   | VARCHAR, CHAR(n), TEXT, CITEXT, NAME |
853/// |                                   | LTREE, LQUERY, LTXTQUERY             |
854/// | `&[u8]`/`Vec<u8>`/`[u8; N]`       | BYTEA                                |
855/// | `HashMap<String, Option<String>>` | HSTORE                               |
856/// | `SystemTime`                      | TIMESTAMP, TIMESTAMP WITH TIME ZONE  |
857/// | `IpAddr`                          | INET                                 |
858///
859/// In addition, some implementations are provided for types in third party
860/// crates. These are disabled by default; to opt into one of these
861/// implementations, activate the Cargo feature corresponding to the crate's
862/// name prefixed by `with-`. For example, the `with-serde_json-1` feature enables
863/// the implementation for the `serde_json::Value` type.
864///
865/// | Rust type                       | Postgres type(s)                    |
866/// |---------------------------------|-------------------------------------|
867/// | `chrono::NaiveDateTime`         | TIMESTAMP                           |
868/// | `chrono::DateTime<Utc>`         | TIMESTAMP WITH TIME ZONE            |
869/// | `chrono::DateTime<Local>`       | TIMESTAMP WITH TIME ZONE            |
870/// | `chrono::DateTime<FixedOffset>` | TIMESTAMP WITH TIME ZONE            |
871/// | `chrono::NaiveDate`             | DATE                                |
872/// | `chrono::NaiveTime`             | TIME                                |
873/// | `cidr::IpCidr`                  | CIDR                                |
874/// | `cidr::IpInet`                  | INET                                |
875/// | `time::PrimitiveDateTime`       | TIMESTAMP                           |
876/// | `time::OffsetDateTime`          | TIMESTAMP WITH TIME ZONE            |
877/// | `time::Date`                    | DATE                                |
878/// | `time::Time`                    | TIME                                |
879/// | `eui48::MacAddress`             | MACADDR                             |
880/// | `geo_types::Point<f64>`         | POINT                               |
881/// | `geo_types::Rect<f64>`          | BOX                                 |
882/// | `geo_types::LineString<f64>`    | PATH                                |
883/// | `serde_json::Value`             | JSON, JSONB                         |
884/// | `uuid::Uuid`                    | UUID                                |
885/// | `bit_vec::BitVec`               | BIT, VARBIT                         |
886/// | `eui48::MacAddress`             | MACADDR                             |
887///
888/// # Nullability
889///
890/// In addition to the types listed above, `ToSql` is implemented for
891/// `Option<T>` where `T` implements `ToSql`. An `Option<T>` represents a
892/// nullable Postgres value.
893///
894/// # Arrays
895///
896/// `ToSql` is implemented for `[u8; N]`, `Vec<T>`, `&[T]`, `Box<[T]>` and `[T; N]`
897/// where `T` implements `ToSql` and `N` is const usize, and corresponds to one-dimensional
898/// Postgres arrays with an index offset of 1.
899/// To make conversion work correctly for `WHERE ... IN` clauses, for example
900/// `WHERE col IN ($1)`, you may instead have to use the construct
901/// `WHERE col = ANY ($1)` which expects an array.
902///
903/// **Note:** the impl for arrays only exist when the Cargo feature `array-impls`
904/// is enabled.
905pub trait ToSql: fmt::Debug {
906    /// Converts the value of `self` into the binary format of the specified
907    /// Postgres `Type`, appending it to `out`.
908    ///
909    /// The caller of this method is responsible for ensuring that this type
910    /// is compatible with the Postgres `Type`.
911    ///
912    /// The return value indicates if this value should be represented as
913    /// `NULL`. If this is the case, implementations **must not** write
914    /// anything to `out`.
915    fn to_sql(&self, ty: &Type, out: &mut BytesMut) -> Result<IsNull, Box<dyn Error + Sync + Send>>
916    where
917        Self: Sized;
918
919    /// Determines if a value of this type can be converted to the specified
920    /// Postgres `Type`.
921    fn accepts(ty: &Type) -> bool
922    where
923        Self: Sized;
924
925    /// An adaptor method used internally by Rust-Postgres.
926    ///
927    /// *All* implementations of this method should be generated by the
928    /// `to_sql_checked!()` macro.
929    fn to_sql_checked(
930        &self,
931        ty: &Type,
932        out: &mut BytesMut,
933    ) -> Result<IsNull, Box<dyn Error + Sync + Send>>;
934
935    /// Specify the encode format
936    fn encode_format(&self, _ty: &Type) -> Format {
937        Format::Binary
938    }
939}
940
941/// Supported Postgres message format types
942///
943/// Using Text format in a message assumes a Postgres `SERVER_ENCODING` of `UTF8`
944#[derive(Clone, Copy, Debug)]
945pub enum Format {
946    /// Text format (UTF-8)
947    Text,
948    /// Compact, typed binary format
949    Binary,
950}
951
952impl<T> ToSql for &T
953where
954    T: ToSql,
955{
956    fn to_sql(
957        &self,
958        ty: &Type,
959        out: &mut BytesMut,
960    ) -> Result<IsNull, Box<dyn Error + Sync + Send>> {
961        (*self).to_sql(ty, out)
962    }
963
964    fn accepts(ty: &Type) -> bool {
965        T::accepts(ty)
966    }
967
968    fn encode_format(&self, ty: &Type) -> Format {
969        (*self).encode_format(ty)
970    }
971
972    to_sql_checked!();
973}
974
975impl<T: ToSql> ToSql for Option<T> {
976    fn to_sql(
977        &self,
978        ty: &Type,
979        out: &mut BytesMut,
980    ) -> Result<IsNull, Box<dyn Error + Sync + Send>> {
981        match *self {
982            Some(ref val) => val.to_sql(ty, out),
983            None => Ok(IsNull::Yes),
984        }
985    }
986
987    fn accepts(ty: &Type) -> bool {
988        <T as ToSql>::accepts(ty)
989    }
990
991    fn encode_format(&self, ty: &Type) -> Format {
992        match self {
993            Some(val) => val.encode_format(ty),
994            None => Format::Binary,
995        }
996    }
997
998    to_sql_checked!();
999}
1000
1001impl<T: ToSql> ToSql for &[T] {
1002    fn to_sql(&self, ty: &Type, w: &mut BytesMut) -> Result<IsNull, Box<dyn Error + Sync + Send>> {
1003        let member_type = match *ty.kind() {
1004            Kind::Array(ref member) => member,
1005            _ => panic!("expected array type"),
1006        };
1007
1008        // Arrays are normally one indexed by default but oidvector and int2vector *require* zero indexing
1009        let lower_bound = match *ty {
1010            Type::OID_VECTOR | Type::INT2_VECTOR => 0,
1011            _ => 1,
1012        };
1013
1014        let dimension = ArrayDimension {
1015            len: downcast(self.len())?,
1016            lower_bound,
1017        };
1018
1019        types::array_to_sql(
1020            Some(dimension),
1021            member_type.oid(),
1022            self.iter(),
1023            |e, w| match e.to_sql(member_type, w)? {
1024                IsNull::No => Ok(postgres_protocol::IsNull::No),
1025                IsNull::Yes => Ok(postgres_protocol::IsNull::Yes),
1026            },
1027            w,
1028        )?;
1029        Ok(IsNull::No)
1030    }
1031
1032    fn accepts(ty: &Type) -> bool {
1033        match *ty.kind() {
1034            Kind::Array(ref member) => T::accepts(member),
1035            _ => false,
1036        }
1037    }
1038
1039    to_sql_checked!();
1040}
1041
1042impl ToSql for &[u8] {
1043    fn to_sql(&self, _: &Type, w: &mut BytesMut) -> Result<IsNull, Box<dyn Error + Sync + Send>> {
1044        types::bytea_to_sql(self, w);
1045        Ok(IsNull::No)
1046    }
1047
1048    accepts!(BYTEA);
1049
1050    to_sql_checked!();
1051}
1052
1053#[cfg(feature = "array-impls")]
1054impl<const N: usize> ToSql for [u8; N] {
1055    fn to_sql(&self, _: &Type, w: &mut BytesMut) -> Result<IsNull, Box<dyn Error + Sync + Send>> {
1056        types::bytea_to_sql(&self[..], w);
1057        Ok(IsNull::No)
1058    }
1059
1060    accepts!(BYTEA);
1061
1062    to_sql_checked!();
1063}
1064
1065#[cfg(feature = "array-impls")]
1066impl<T: ToSql, const N: usize> ToSql for [T; N] {
1067    fn to_sql(&self, ty: &Type, w: &mut BytesMut) -> Result<IsNull, Box<dyn Error + Sync + Send>> {
1068        <&[T] as ToSql>::to_sql(&&self[..], ty, w)
1069    }
1070
1071    fn accepts(ty: &Type) -> bool {
1072        <&[T] as ToSql>::accepts(ty)
1073    }
1074
1075    to_sql_checked!();
1076}
1077
1078impl<T: ToSql> ToSql for Vec<T> {
1079    fn to_sql(&self, ty: &Type, w: &mut BytesMut) -> Result<IsNull, Box<dyn Error + Sync + Send>> {
1080        <&[T] as ToSql>::to_sql(&&**self, ty, w)
1081    }
1082
1083    fn accepts(ty: &Type) -> bool {
1084        <&[T] as ToSql>::accepts(ty)
1085    }
1086
1087    to_sql_checked!();
1088}
1089
1090impl<T: ToSql> ToSql for Box<T> {
1091    fn to_sql(&self, ty: &Type, w: &mut BytesMut) -> Result<IsNull, Box<dyn Error + Sync + Send>> {
1092        <&T as ToSql>::to_sql(&&**self, ty, w)
1093    }
1094
1095    fn accepts(ty: &Type) -> bool {
1096        <&T as ToSql>::accepts(ty)
1097    }
1098
1099    to_sql_checked!();
1100}
1101
1102impl<T: ToSql> ToSql for Box<[T]> {
1103    fn to_sql(&self, ty: &Type, w: &mut BytesMut) -> Result<IsNull, Box<dyn Error + Sync + Send>> {
1104        <&[T] as ToSql>::to_sql(&&**self, ty, w)
1105    }
1106
1107    fn accepts(ty: &Type) -> bool {
1108        <&[T] as ToSql>::accepts(ty)
1109    }
1110
1111    to_sql_checked!();
1112}
1113
1114impl ToSql for Cow<'_, [u8]> {
1115    fn to_sql(&self, ty: &Type, w: &mut BytesMut) -> Result<IsNull, Box<dyn Error + Sync + Send>> {
1116        <&[u8] as ToSql>::to_sql(&self.as_ref(), ty, w)
1117    }
1118
1119    fn accepts(ty: &Type) -> bool {
1120        <&[u8] as ToSql>::accepts(ty)
1121    }
1122
1123    to_sql_checked!();
1124}
1125
1126impl ToSql for Vec<u8> {
1127    fn to_sql(&self, ty: &Type, w: &mut BytesMut) -> Result<IsNull, Box<dyn Error + Sync + Send>> {
1128        <&[u8] as ToSql>::to_sql(&&**self, ty, w)
1129    }
1130
1131    fn accepts(ty: &Type) -> bool {
1132        <&[u8] as ToSql>::accepts(ty)
1133    }
1134
1135    to_sql_checked!();
1136}
1137
1138impl ToSql for &str {
1139    fn to_sql(&self, ty: &Type, w: &mut BytesMut) -> Result<IsNull, Box<dyn Error + Sync + Send>> {
1140        match ty.name() {
1141            "ltree" => types::ltree_to_sql(self, w),
1142            "lquery" => types::lquery_to_sql(self, w),
1143            "ltxtquery" => types::ltxtquery_to_sql(self, w),
1144            _ => types::text_to_sql(self, w),
1145        }
1146        Ok(IsNull::No)
1147    }
1148
1149    fn accepts(ty: &Type) -> bool {
1150        matches!(
1151            *ty,
1152            Type::VARCHAR | Type::TEXT | Type::BPCHAR | Type::NAME | Type::UNKNOWN
1153        ) || matches!(ty.name(), "citext" | "ltree" | "lquery" | "ltxtquery")
1154    }
1155
1156    to_sql_checked!();
1157}
1158
1159impl ToSql for Cow<'_, str> {
1160    fn to_sql(&self, ty: &Type, w: &mut BytesMut) -> Result<IsNull, Box<dyn Error + Sync + Send>> {
1161        <&str as ToSql>::to_sql(&self.as_ref(), ty, w)
1162    }
1163
1164    fn accepts(ty: &Type) -> bool {
1165        <&str as ToSql>::accepts(ty)
1166    }
1167
1168    to_sql_checked!();
1169}
1170
1171impl ToSql for String {
1172    fn to_sql(&self, ty: &Type, w: &mut BytesMut) -> Result<IsNull, Box<dyn Error + Sync + Send>> {
1173        <&str as ToSql>::to_sql(&&**self, ty, w)
1174    }
1175
1176    fn accepts(ty: &Type) -> bool {
1177        <&str as ToSql>::accepts(ty)
1178    }
1179
1180    to_sql_checked!();
1181}
1182
1183impl ToSql for Box<str> {
1184    fn to_sql(&self, ty: &Type, w: &mut BytesMut) -> Result<IsNull, Box<dyn Error + Sync + Send>> {
1185        <&str as ToSql>::to_sql(&&**self, ty, w)
1186    }
1187
1188    fn accepts(ty: &Type) -> bool {
1189        <&str as ToSql>::accepts(ty)
1190    }
1191
1192    to_sql_checked!();
1193}
1194
1195macro_rules! simple_to {
1196    ($t:ty, $f:ident, $($expected:ident),+) => {
1197        impl ToSql for $t {
1198            fn to_sql(&self,
1199                      _: &Type,
1200                      w: &mut BytesMut)
1201                      -> Result<IsNull, Box<dyn Error + Sync + Send>> {
1202                types::$f(*self, w);
1203                Ok(IsNull::No)
1204            }
1205
1206            accepts!($($expected),+);
1207
1208            to_sql_checked!();
1209        }
1210    }
1211}
1212
1213simple_to!(bool, bool_to_sql, BOOL);
1214simple_to!(i8, char_to_sql, CHAR);
1215simple_to!(i16, int2_to_sql, INT2);
1216simple_to!(i32, int4_to_sql, INT4);
1217simple_to!(u32, oid_to_sql, OID);
1218simple_to!(i64, int8_to_sql, INT8);
1219simple_to!(f32, float4_to_sql, FLOAT4);
1220simple_to!(f64, float8_to_sql, FLOAT8);
1221
1222impl<H> ToSql for HashMap<String, Option<String>, H>
1223where
1224    H: BuildHasher,
1225{
1226    fn to_sql(&self, _: &Type, w: &mut BytesMut) -> Result<IsNull, Box<dyn Error + Sync + Send>> {
1227        types::hstore_to_sql(
1228            self.iter().map(|(k, v)| (&**k, v.as_ref().map(|v| &**v))),
1229            w,
1230        )?;
1231        Ok(IsNull::No)
1232    }
1233
1234    fn accepts(ty: &Type) -> bool {
1235        ty.name() == "hstore"
1236    }
1237
1238    to_sql_checked!();
1239}
1240
1241impl ToSql for SystemTime {
1242    fn to_sql(&self, _: &Type, w: &mut BytesMut) -> Result<IsNull, Box<dyn Error + Sync + Send>> {
1243        let epoch = UNIX_EPOCH + Duration::from_secs(TIME_SEC_CONVERSION);
1244
1245        let to_usec =
1246            |d: Duration| d.as_secs() * USEC_PER_SEC + u64::from(d.subsec_nanos()) / NSEC_PER_USEC;
1247
1248        let time = match self.duration_since(epoch) {
1249            Ok(duration) => to_usec(duration) as i64,
1250            Err(e) => -(to_usec(e.duration()) as i64),
1251        };
1252
1253        types::timestamp_to_sql(time, w);
1254        Ok(IsNull::No)
1255    }
1256
1257    accepts!(TIMESTAMP, TIMESTAMPTZ);
1258
1259    to_sql_checked!();
1260}
1261
1262impl ToSql for IpAddr {
1263    fn to_sql(&self, _: &Type, w: &mut BytesMut) -> Result<IsNull, Box<dyn Error + Sync + Send>> {
1264        let netmask = match self {
1265            IpAddr::V4(_) => 32,
1266            IpAddr::V6(_) => 128,
1267        };
1268        types::inet_to_sql(*self, netmask, w);
1269        Ok(IsNull::No)
1270    }
1271
1272    accepts!(INET);
1273
1274    to_sql_checked!();
1275}
1276
1277fn downcast(len: usize) -> Result<i32, Box<dyn Error + Sync + Send>> {
1278    if len > i32::MAX as usize {
1279        Err("value too large to transmit".into())
1280    } else {
1281        Ok(len as i32)
1282    }
1283}
1284
1285mod sealed {
1286    pub trait Sealed {}
1287}
1288
1289/// A trait used by clients to abstract over `&dyn ToSql` and `T: ToSql`.
1290///
1291/// This cannot be implemented outside of this crate.
1292pub trait BorrowToSql: sealed::Sealed {
1293    /// Returns a reference to `self` as a `ToSql` trait object.
1294    fn borrow_to_sql(&self) -> &dyn ToSql;
1295}
1296
1297impl sealed::Sealed for &dyn ToSql {}
1298
1299impl BorrowToSql for &dyn ToSql {
1300    #[inline]
1301    fn borrow_to_sql(&self) -> &dyn ToSql {
1302        *self
1303    }
1304}
1305
1306impl sealed::Sealed for Box<dyn ToSql + Sync + '_> {}
1307
1308impl BorrowToSql for Box<dyn ToSql + Sync + '_> {
1309    #[inline]
1310    fn borrow_to_sql(&self) -> &dyn ToSql {
1311        self.as_ref()
1312    }
1313}
1314
1315impl sealed::Sealed for Box<dyn ToSql + Sync + Send + '_> {}
1316impl BorrowToSql for Box<dyn ToSql + Sync + Send + '_> {
1317    #[inline]
1318    fn borrow_to_sql(&self) -> &dyn ToSql {
1319        self.as_ref()
1320    }
1321}
1322
1323impl sealed::Sealed for &(dyn ToSql + Sync) {}
1324
1325/// In async contexts it is sometimes necessary to have the additional
1326/// Sync requirement on parameters for queries since this enables the
1327/// resulting Futures to be Send, hence usable in, e.g., tokio::spawn.
1328/// This instance is provided for those cases.
1329impl BorrowToSql for &(dyn ToSql + Sync) {
1330    #[inline]
1331    fn borrow_to_sql(&self) -> &dyn ToSql {
1332        *self
1333    }
1334}
1335
1336impl<T> sealed::Sealed for T where T: ToSql {}
1337
1338impl<T> BorrowToSql for T
1339where
1340    T: ToSql,
1341{
1342    #[inline]
1343    fn borrow_to_sql(&self) -> &dyn ToSql {
1344        self
1345    }
1346}