diesel_citext/
types.rs

1use std::borrow::Borrow;
2use std::cmp::{Eq, PartialEq};
3use std::error::Error;
4use std::fmt;
5use std::hash::{Hash, Hasher};
6use std::io::prelude::*;
7use std::ops::Deref;
8use std::str::FromStr;
9use diesel::deserialize::{self, FromSql};
10use diesel::serialize::{self, IsNull, Output, ToSql};
11use diesel::pg::Pg;
12use serde::{Serialize, Deserialize};
13use crate::sql_types::*;
14
15#[cfg(feature = "with-actix-web")]
16use actix_web::dev::FromParam;
17
18/// `CiString` is a CaseInsenstive String type that can be used as the key for
19/// a hashmap as well as be written to the page. It implements a variety of traits
20/// to make it easy to convert from and to &str and String types.
21#[derive(Clone, Debug, Serialize, Deserialize, FromSqlRow, AsExpression)]
22#[sql_type = "Citext"]
23pub struct CiString {
24    value: String,
25}
26
27
28impl CiString {
29    pub fn new() -> Self {
30        CiString {
31            value: String::new(),
32        }
33    }
34}
35
36/// CiString can implement the FromParam trait from ActixWeb if "with-actix-web" is
37/// turned on in the Cargo.toml file. 
38#[cfg(feature = "with-actix-web")]
39impl FromParam for CiString {
40    type Err = actix_web::error::UrlParseError;
41    fn from_param(s: &str) -> Result<Self, Self::Err> {
42        Ok(CiString {
43            value: s.to_lowercase()
44        })
45    }
46}
47
48impl fmt::Display for CiString {
49    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
50        write!(f, "{}", self.value)
51    }
52}
53
54impl PartialEq for CiString {
55    fn eq(&self, other: &CiString) -> bool {
56        self.value == other.value
57    }
58}
59
60impl PartialEq<String> for CiString {
61    fn eq(&self, other: &String) -> bool {
62        self.value == other.to_lowercase()
63    }
64}
65
66impl PartialEq<&str> for CiString {
67    fn eq(&self, other: &&str) -> bool {
68        self.value == other.to_lowercase()
69    }
70}
71
72impl Eq for CiString {
73
74}
75
76impl Hash for CiString {
77    fn hash<H: Hasher>(&self, hasher: &mut H) {
78        self.value.hash(hasher);
79    }
80}
81
82impl AsRef<str> for CiString {
83    fn as_ref(&self) -> &str {
84        &*self.value
85    }
86}
87
88impl Borrow<str> for CiString {
89    fn borrow(&self) -> &str {
90        &*self.value
91    }
92}
93
94impl Deref for CiString {
95    type Target = String;
96
97    fn deref(&self) -> &String {
98        &self.value
99    }
100}
101
102impl FromStr for CiString {
103    type Err = fmt::Error;
104    fn from_str(s: &str) -> Result<Self, Self::Err> {
105        Ok(CiString { value: s.to_lowercase() })
106    }
107}
108
109impl Into<String> for CiString {
110    fn into(self) -> String {
111        self.value
112    }
113}
114
115impl From<String> for CiString {
116    fn from(value: String) ->  Self {
117        CiString {
118            value: value.to_lowercase()
119        }
120    }
121}
122
123impl From<&str> for CiString {
124    fn from(value: &str) ->  Self {
125        CiString {
126            value: value.to_lowercase()
127        }
128    }
129}
130
131impl FromSql<Citext, Pg> for CiString {
132	fn from_sql(bytes: Option<&[u8]>) -> deserialize::Result<Self> {
133		use std::str;
134        let string = str::from_utf8(not_none!(bytes))?;
135        Ok(CiString{ value: string.to_lowercase() })
136	}
137}
138
139impl ToSql<Citext, Pg> for CiString {
140	fn to_sql<W: Write>(&self, out: &mut Output<W, Pg>) -> serialize::Result {
141        out.write_all(self.value.as_bytes())
142            .map(|_| IsNull::No)
143            .map_err(|e| Box::new(e) as Box<Error + Send + Sync>)
144	}
145}
146
147impl FromSql<Citext, Pg> for String {
148	fn from_sql(bytes: Option<&[u8]>) -> deserialize::Result<Self> {
149		use std::str;
150        let string = str::from_utf8(not_none!(bytes))?;
151        Ok(string.to_lowercase())
152	}
153}
154
155impl ToSql<Citext, Pg> for String {
156	fn to_sql<W: Write>(&self, out: &mut Output<W, Pg>) -> serialize::Result {
157        out.write_all(self.to_lowercase().as_bytes())
158            .map(|_| IsNull::No)
159            .map_err(|e| Box::new(e) as Box<Error + Send + Sync>)
160	}
161}
162
163impl ToSql<Citext, Pg> for str {
164	fn to_sql<W: Write>(&self, out: &mut Output<W, Pg>) -> serialize::Result {
165        out.write_all(self.to_lowercase().as_bytes())
166            .map(|_| IsNull::No)
167            .map_err(|e| Box::new(e) as Box<Error + Send + Sync>)
168	}
169}
170