Skip to content

Commit 1f7ad4b

Browse files
committed
via_string WIP
1 parent ea374c0 commit 1f7ad4b

File tree

2 files changed

+213
-0
lines changed

2 files changed

+213
-0
lines changed

rust/functora-tagged/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ use std::ops::Deref;
88
use std::str::FromStr;
99
pub mod infallible;
1010
pub use infallible::*;
11+
pub mod via_string;
12+
pub use via_string::*;
1113

1214
#[derive(Debug)]
1315
pub struct Tagged<Rep, Tag>(Rep, PhantomData<Tag>);
Lines changed: 211 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,211 @@
1+
use crate::infallible::*;
2+
use crate::*;
3+
use derive_more::Display;
4+
use std::error::Error;
5+
use std::fmt::{Debug, Display};
6+
use std::hash::{Hash, Hasher};
7+
use std::marker::PhantomData;
8+
use std::ops::Deref;
9+
use std::str::FromStr;
10+
11+
#[derive(Debug)]
12+
pub struct ViaString<Rep, Tag>(Rep, PhantomData<Tag>);
13+
14+
impl<Rep, Tag> ViaString<Rep, Tag> {
15+
pub fn new(rep: Rep) -> Result<Self, Tag::RefineError>
16+
where
17+
Tag: Refine<Rep>,
18+
{
19+
Tag::refine(rep)
20+
.map(|rep| ViaString(rep, PhantomData))
21+
}
22+
pub fn rep(&self) -> &Rep {
23+
&self.0
24+
}
25+
}
26+
27+
impl<Rep: Eq, Tag> Eq for ViaString<Rep, Tag> {}
28+
29+
impl<Rep: PartialEq, Tag> PartialEq
30+
for ViaString<Rep, Tag>
31+
{
32+
fn eq(&self, other: &Self) -> bool {
33+
self.rep() == other.rep()
34+
}
35+
}
36+
37+
impl<Rep: Ord, Tag> Ord for ViaString<Rep, Tag> {
38+
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
39+
self.rep().cmp(other.rep())
40+
}
41+
}
42+
43+
impl<Rep: PartialOrd, Tag> PartialOrd
44+
for ViaString<Rep, Tag>
45+
{
46+
fn partial_cmp(
47+
&self,
48+
other: &Self,
49+
) -> Option<std::cmp::Ordering> {
50+
self.rep().partial_cmp(other.rep())
51+
}
52+
}
53+
54+
impl<Rep: Clone, Tag> Clone for ViaString<Rep, Tag> {
55+
fn clone(&self) -> Self {
56+
ViaString(self.rep().clone(), PhantomData)
57+
}
58+
}
59+
60+
impl<Rep: Display, Tag> Display for ViaString<Rep, Tag> {
61+
fn fmt(
62+
&self,
63+
f: &mut std::fmt::Formatter<'_>,
64+
) -> std::fmt::Result {
65+
self.rep().fmt(f)
66+
}
67+
}
68+
69+
impl<Rep: Hash, Tag> Hash for ViaString<Rep, Tag> {
70+
fn hash<H: Hasher>(&self, state: &mut H) {
71+
self.rep().hash(state);
72+
}
73+
}
74+
75+
impl<Rep, Tag> Deref for ViaString<Rep, Tag> {
76+
type Target = Rep;
77+
78+
fn deref(&self) -> &Self::Target {
79+
self.rep()
80+
}
81+
}
82+
83+
impl<Rep, Tag> FromStr for ViaString<Rep, Tag>
84+
where
85+
Rep: FromStr,
86+
Tag: Refine<Rep>,
87+
{
88+
type Err = ParseError<Rep, Tag>;
89+
fn from_str(s: &str) -> Result<Self, Self::Err> {
90+
ViaString::new(
91+
Rep::from_str(s).map_err(ParseError::Decode)?,
92+
)
93+
.map_err(ParseError::Refine)
94+
}
95+
}
96+
97+
#[cfg(feature = "serde")]
98+
use serde::{Deserialize, Serialize};
99+
100+
#[cfg(feature = "serde")]
101+
impl<Rep: Serialize, Tag> Serialize for Tagged<Rep, Tag> {
102+
fn serialize<S>(
103+
&self,
104+
serializer: S,
105+
) -> Result<S::Ok, S::Error>
106+
where
107+
S: serde::Serializer,
108+
{
109+
self.rep().serialize(serializer)
110+
}
111+
}
112+
113+
#[cfg(feature = "serde")]
114+
impl<'de, Rep, Tag> Deserialize<'de> for Tagged<Rep, Tag>
115+
where
116+
Rep: Deserialize<'de>,
117+
Tag: Refine<Rep>,
118+
Tag::RefineError: Display,
119+
{
120+
fn deserialize<D>(
121+
deserializer: D,
122+
) -> Result<Self, D::Error>
123+
where
124+
D: serde::Deserializer<'de>,
125+
{
126+
Rep::deserialize(deserializer).and_then(|rep| {
127+
Tagged::new(rep)
128+
.map_err(serde::de::Error::custom)
129+
})
130+
}
131+
}
132+
133+
#[cfg(feature = "diesel")]
134+
mod diesel_impl {
135+
use crate::*;
136+
use diesel::Queryable;
137+
use diesel::backend::Backend;
138+
use diesel::deserialize::FromSql;
139+
use diesel::expression::AsExpression;
140+
use diesel::serialize::{Output, ToSql};
141+
use diesel::sql_types::SingleValue;
142+
use std::error::Error;
143+
144+
impl<Rep, Tag, ST> AsExpression<ST> for Tagged<Rep, Tag>
145+
where
146+
Rep: Clone + AsExpression<ST>,
147+
ST: SingleValue,
148+
{
149+
type Expression = Rep::Expression;
150+
fn as_expression(self) -> Self::Expression {
151+
self.rep().clone().as_expression()
152+
}
153+
}
154+
155+
impl<Rep, Tag, ST> AsExpression<ST> for &Tagged<Rep, Tag>
156+
where
157+
Rep: Clone + AsExpression<ST>,
158+
ST: SingleValue,
159+
{
160+
type Expression = Rep::Expression;
161+
fn as_expression(self) -> Self::Expression {
162+
self.rep().clone().as_expression()
163+
}
164+
}
165+
166+
impl<DB, Rep, Tag, ST> ToSql<ST, DB> for Tagged<Rep, Tag>
167+
where
168+
Rep: ToSql<ST, DB>,
169+
DB: Backend,
170+
Tag: Debug,
171+
{
172+
fn to_sql<'a>(
173+
&'a self,
174+
out: &mut Output<'a, '_, DB>,
175+
) -> diesel::serialize::Result {
176+
self.rep().to_sql(out)
177+
}
178+
}
179+
180+
impl<DB, Rep, Tag, ST> FromSql<ST, DB> for Tagged<Rep, Tag>
181+
where
182+
Rep: FromSql<ST, DB>,
183+
Tag: Refine<Rep>,
184+
Tag::RefineError: 'static + Error + Send + Sync,
185+
DB: Backend,
186+
{
187+
fn from_sql(
188+
bytes: DB::RawValue<'_>,
189+
) -> diesel::deserialize::Result<Self> {
190+
let rep = Rep::from_sql(bytes)?;
191+
Ok(Tagged::new(rep).map_err(Box::new)?)
192+
}
193+
}
194+
195+
impl<Rep, Tag, ST, DB> Queryable<ST, DB>
196+
for Tagged<Rep, Tag>
197+
where
198+
Rep: Queryable<ST, DB>,
199+
Tag: Refine<Rep>,
200+
Tag::RefineError: 'static + Error + Send + Sync,
201+
DB: Backend,
202+
{
203+
type Row = Rep::Row;
204+
fn build(
205+
row: Self::Row,
206+
) -> diesel::deserialize::Result<Self> {
207+
let rep = Queryable::build(row)?;
208+
Ok(Tagged::new(rep).map_err(Box::new)?)
209+
}
210+
}
211+
}

0 commit comments

Comments
 (0)