1#![no_std]
2#![deny(missing_docs)]
3
4#[cfg(test)]
7#[macro_use]
8extern crate std;
9
10pub trait Property {
12 type Value;
14
15 type Error;
17
18 fn validate(value: &Self::Value) -> Result<(), Self::Error>;
20}
21
22pub struct TypedValue<P: Property> {
24 inner: P::Value,
25}
26
27impl<P: Property> TypedValue<P> {
28 pub fn new(value: P::Value) -> Result<Self, P::Error> {
55 P::validate(&value)?;
56
57 Ok(TypedValue { inner: value })
58 }
59}
60
61impl<P: Property<Value = V>, V: PartialEq> PartialEq for TypedValue<P> {
62 fn eq(&self, other: &Self) -> bool {
63 V::eq(&self.inner, &other.inner)
64 }
65}
66
67impl<P: Property<Value = V>, V: Eq> Eq for TypedValue<P> {}
68
69impl<P: Property<Value = V>, V: PartialOrd> PartialOrd for TypedValue<P> {
70 fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
71 V::partial_cmp(&self.inner, &other.inner)
72 }
73
74 fn lt(&self, other: &Self) -> bool {
75 V::lt(&self.inner, &other.inner)
76 }
77
78 fn le(&self, other: &Self) -> bool {
79 V::le(&self.inner, &other.inner)
80 }
81
82 fn gt(&self, other: &Self) -> bool {
83 V::gt(&self.inner, &other.inner)
84 }
85
86 fn ge(&self, other: &Self) -> bool {
87 V::ge(&self.inner, &other.inner)
88 }
89}
90
91impl<P: Property<Value = V>, V: Ord> Ord for TypedValue<P> {
92 fn cmp(&self, other: &Self) -> core::cmp::Ordering {
93 V::cmp(&self.inner, &other.inner)
94 }
95}
96
97impl<P: Property<Value = V>, V: core::hash::Hash> core::hash::Hash for TypedValue<P> {
98 fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
99 V::hash(&self.inner, state);
100 }
101}
102
103impl<P: Property<Value = V>, V: Clone> Clone for TypedValue<P> {
104 fn clone(&self) -> Self {
105 Self {
106 inner: V::clone(&self.inner),
107 }
108 }
109}
110
111impl<P: Property<Value = V>, V: Copy> Copy for TypedValue<P> {}
112
113impl<P: Property<Value = V>, V: core::fmt::Debug> core::fmt::Debug for TypedValue<P> {
114 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
115 V::fmt(&self.inner, f)
116 }
117}
118
119impl<P: Property<Value = V>, V: core::fmt::Display> core::fmt::Display for TypedValue<P> {
120 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
121 V::fmt(&self.inner, f)
122 }
123}
124
125impl<P: Property> core::ops::Deref for TypedValue<P> {
126 type Target = P::Value;
127
128 fn deref(&self) -> &Self::Target {
129 &self.inner
130 }
131}
132
133pub trait TypedValueExt: Sized {
135 fn typed<P: Property<Value = Self>>(self) -> Result<TypedValue<P>, P::Error>;
161}
162
163impl<T> TypedValueExt for T {
164 fn typed<P: Property<Value = Self>>(self) -> Result<TypedValue<P>, P::Error> {
165 TypedValue::new(self)
166 }
167}
168
169#[cfg(test)]
170mod property_based_tests {
171 use super::*;
172 use quickcheck_macros::quickcheck;
173
174 struct Stub<T>(T);
175
176 impl<T> Property for Stub<T> {
177 type Value = T;
178 type Error = ();
179
180 fn validate(_: &Self::Value) -> Result<(), Self::Error> {
181 Ok(())
182 }
183 }
184
185 #[quickcheck]
186 fn equivalent_when_wrapped_and_then_unwrapped(value: u8) {
187 assert_eq!(*TypedValue::<Stub<_>>::new(value).unwrap(), value)
188 }
189}