Skip to content

Commit b11ae1a

Browse files
committed
update README
1 parent 5f14fba commit b11ae1a

File tree

1 file changed

+66
-43
lines changed

1 file changed

+66
-43
lines changed

README.md

+66-43
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,18 @@
11
# Refined-Type
2-
**refined-type** is a library developed for Rust. It enhances your types, making them more robust and expanding the range of guarantees your applications can statically ensure.
2+
3+
**refined-type** is a library developed for Rust. It enhances your types, making them more robust and expanding the
4+
range of guarantees your applications can statically ensure.
35

46
# Overview
5-
You can create various rules for a certain type, such as phone numbers, addresses, times, and so on.
6-
Once you have established the rules, you can easily combine them.
7-
Specifically, if you create rules for 'non-empty strings' and 'strings composed only of alphabets,' you do not need to redefine a new rule for 'non-empty strings composed only of alphabets'.
7+
8+
You can create various rules for a certain type, such as phone numbers, addresses, times, and so on.
9+
Once you have established the rules, you can easily combine them.
10+
Specifically, if you create rules for 'non-empty strings' and 'strings composed only of alphabets,' you do not need to
11+
redefine a new rule for 'non-empty strings composed only of alphabets'.
812
All rules can be arbitrarily combined and extended as long as the target type matches. Enjoy a wonderful type life!
913

1014
# Example Usage
15+
1116
```rust
1217
type NonEmptyString = Refined<NonEmptyStringRule>;
1318

@@ -21,15 +26,17 @@ fn main() {
2126
```
2227

2328
# Installation
29+
2430
```shell
2531
cargo add refined-type
2632
```
2733

2834
# Custom Rule
29-
There are many situations where you may want to define custom rules.
30-
To define rules for a specific target type, you first need to define a struct.
31-
In the struct, define fields for specifying detailed conditions.
32-
Once the definition is complete, all you need to do is implement the Rule trait.
35+
36+
There are many situations where you may want to define custom rules.
37+
To define rules for a specific target type, you first need to define a struct.
38+
In the struct, define fields for specifying detailed conditions.
39+
Once the definition is complete, all you need to do is implement the Rule trait.
3340
Add your preferred conditions as you like.
3441

3542
```rust
@@ -38,20 +45,23 @@ fn main() {
3845
assert_eq!(non_empty_string_result.unwrap().deref(), "Hello World");
3946

4047
let empty_string_result = Refined::<NonEmptyStringRule>::new("".to_string());
41-
assert!(empty_string_result.is_err())
48+
assert!(empty_string_result.is_err())
4249
}
4350
```
4451

4552
# Compose Rules
46-
As mentioned earlier, it is possible to combine any rules as long as the target types match.
47-
In the example below, there are standalone rules for 'strings containing Hello' and 'strings containing World'.
48-
Since their target type is String, combining them is possible.
49-
I have prepared something called Rule Composer (`And`, `Or`, `Not`).
53+
54+
As mentioned earlier, it is possible to combine any rules as long as the target types match.
55+
In the example below, there are standalone rules for 'strings containing Hello' and 'strings containing World'.
56+
Since their target type is String, combining them is possible.
57+
I have prepared something called Rule Composer (`And`, `Or`, `Not`).
5058
By using Rule Composer, composite rules can be easily created.
5159

5260
### Original Rules
61+
5362
```rust
5463
struct ContainsHelloRule;
64+
5565
struct ContainsWorldRule;
5666

5767
impl Rule for ContainsHelloRule {
@@ -60,8 +70,7 @@ impl Rule for ContainsHelloRule {
6070
fn validate(target: Self::Item) -> Result<Self::Item, Error<Self::Item>> {
6171
if target.contains("Hello") {
6272
Ok(target)
63-
}
64-
else {
73+
} else {
6574
Err(Error::new(format!("{} does not contain `Hello`", target)))
6675
}
6776
}
@@ -73,17 +82,18 @@ impl Rule for ContainsWorldRule {
7382
fn validate(target: Self::Item) -> Result<Self::Item, Error<Self::Item>> {
7483
if target.contains("World") {
7584
Ok(target)
76-
}
77-
else {
85+
} else {
7886
Err(Error::new(format!("{} does not contain `World`", target)))
7987
}
8088
}
8189
}
8290
```
8391

8492
### 1: `And` Rule Composer
85-
`And` Rule Composer is a rule that satisfies both of the two rules.
93+
94+
`And` Rule Composer is a rule that satisfies both of the two rules.
8695
It is generally effective when you want to narrow down the condition range.
96+
8797
```rust
8898
fn main() {
8999
type HelloAndWorldRule = And<ContainsHelloRule, ContainsWorldRule>;
@@ -97,8 +107,10 @@ fn main() {
97107
```
98108

99109
### 2: `Or` Rule Composer
100-
`Or` Rule Composer is a rule that satisfies either of the two rules.
110+
111+
`Or` Rule Composer is a rule that satisfies either of the two rules.
101112
It is generally effective when you want to expand the condition range.
113+
102114
```rust
103115
fn main() {
104116
type HelloOrWorldRule = Or<ContainsHelloRule, ContainsWorldRule>;
@@ -115,8 +127,10 @@ fn main() {
115127
```
116128

117129
### 3: `Not` Rule Composer
118-
`Not` Rule Composer is a rule that does not satisfy a specific condition.
130+
131+
`Not` Rule Composer is a rule that does not satisfy a specific condition.
119132
It is generally effective when you want to discard only certain situations.
133+
120134
```rust
121135
fn main() {
122136
type NotHelloRule = Not<ContainsHelloRule>;
@@ -130,11 +144,15 @@ fn main() {
130144
```
131145

132146
### 4: Compose Rule Composer
133-
Rule Composer is also a rule.
147+
148+
Rule Composer is also a rule.
134149
Therefore, it can be treated much like a composite function
150+
135151
```rust
136152
struct StartWithHelloRule;
153+
137154
struct StartWithByeRule;
155+
138156
struct EndWithJohnRule;
139157

140158
impl Rule for StartsWithHelloRule {
@@ -143,8 +161,7 @@ impl Rule for StartsWithHelloRule {
143161
fn validate(target: Self::Item) -> Result<Self::Item, Error<Self::Item>> {
144162
if target.starts_with("Hello") {
145163
Ok(target)
146-
}
147-
else {
164+
} else {
148165
Err(Error::new(format!("{} does not start with `Hello`", target)))
149166
}
150167
}
@@ -156,8 +173,7 @@ impl Rule for StartsWithByeRule {
156173
fn validate(target: Self::Item) -> Result<Self::Item, Error<Self::Item>> {
157174
if target.starts_with("Bye") {
158175
Ok(target)
159-
}
160-
else {
176+
} else {
161177
Err(Error::new(format!("{} does not start with `Bye`", target)))
162178
}
163179
}
@@ -169,8 +185,7 @@ impl Rule for EndWithJohnRule {
169185
fn validate(target: Self::Item) -> Result<Self::Item, Error<Self::Item>> {
170186
if target.ends_with("John") {
171187
Ok(target)
172-
}
173-
else {
188+
} else {
174189
Err(Error::new(format!("{} does not end with `John`", target)))
175190
}
176191
}
@@ -187,8 +202,13 @@ fn main() {
187202
```
188203

189204
# JSON
190-
`refined_type` is compatible with `serde_json`. This ensures type-safe communication and eliminates the need to write new validation processes. All you need to do is implement a set of rules once and implement `serde`’s `Serialize` and `Deserialize`.
205+
206+
`refined_type` is compatible with `serde_json`. This ensures type-safe communication and eliminates the need to write
207+
new validation processes. All you need to do is implement a set of rules once and implement `serde`’s `Serialize`
208+
and `Deserialize`.
209+
191210
### Serialize
211+
192212
```rust
193213
type NonEmptyString = Refined<NonEmptyStringRule>;
194214

@@ -215,6 +235,7 @@ fn main() -> anyhow::Result<()> {
215235
```
216236

217237
### Deserialize
238+
218239
```rust
219240
type NonEmptyString = Refined<NonEmptyStringRule>;
220241

@@ -229,7 +250,7 @@ fn main() -> anyhow::Result<()> {
229250
"name": "john",
230251
"age": 8
231252
}}
232-
.to_string();
253+
.to_string();
233254

234255
let actual = serde_json::from_str::<Human>(&json)?;
235256

@@ -241,10 +262,13 @@ fn main() -> anyhow::Result<()> {
241262
Ok(())
242263
}
243264
```
265+
244266
# Number
267+
245268
You can also represent the size of numbers as types.
246269
I have prepared macros that can easily define the size of numbers.
247270
Let’s use them to define a `Age` type that is narrowed down to ages 18 to 80.
271+
248272
```rust
249273
greater_rule!((18, u8));
250274
less_rule!((80, u8));
@@ -263,11 +287,13 @@ type TargetAgeRule = And<TargetAge18OrMore, TargetAge80OrLess>;
263287
```
264288

265289
# Iterator
290+
266291
The Iterator I’ve prepared has `into_iter` and `iter` implemented.
267292
Therefore, you can easily map or convert it to a different Iterator using `collect`.
268293
Feel free to explore the capabilities of the Iterator you’ve been given!
269294

270295
### `into_iter()`
296+
271297
```rust
272298
fn main() -> anyhow::Result<()> {
273299
let ne_vec = NonEmptyVec::new(vec![1, 2, 3])?;
@@ -278,6 +304,7 @@ fn main() -> anyhow::Result<()> {
278304
```
279305

280306
### `iter()`
307+
281308
```rust
282309
fn main() -> anyhow::Result<()> {
283310
let ne_vec = NonEmptyVec::new(vec![1, 2, 3])?;
@@ -288,6 +315,7 @@ fn main() -> anyhow::Result<()> {
288315
```
289316

290317
### `NonEmptyVec` to `NonEmptyVecDeque` using `collect()`
318+
291319
```rust
292320
fn main() -> anyhow::Result<()> {
293321
let ne_vec = NonEmptyVec::new(vec![1, 2, 3])?;
@@ -298,8 +326,12 @@ fn main() -> anyhow::Result<()> {
298326
```
299327

300328
# Add Trait
301-
I have implemented the `Add` trait for a part of the `Refined` that I provided. Therefore, operations can be performed without downgrading the type level.
329+
330+
I have implemented the `Add` trait for a part of the `Refined` that I provided. Therefore, operations can be performed
331+
without downgrading the type level.
332+
302333
### NonEmptyString
334+
303335
```rust
304336
fn main() -> anyhow::Result<()> {
305337
let non_empty_string_1 = NonEmptyString::new("Hello".to_string())?;
@@ -312,6 +344,7 @@ fn main() -> anyhow::Result<()> {
312344
```
313345

314346
### NonEmptyVec
347+
315348
```rust
316349
fn main() -> anyhow::Result<()> {
317350
let ne_vec_1 = NonEmptyVec::new(vec![1, 2, 3])?;
@@ -323,20 +356,9 @@ fn main() -> anyhow::Result<()> {
323356
}
324357
```
325358

326-
### Empty
327-
```rust
328-
fn main() -> anyhow::Result<()> {
329-
let empty_1 = Empty::new(0)?;
330-
let empty_2 = Empty::new(0)?;
331-
let empty = empty_1 + empty_2; // This is also `Empty` type
332-
333-
assert_eq!(empty.into_value(), 0);
334-
Ok(())
335-
}
336-
```
337-
338359
# Tips
339-
Directly writing `And`, `Or`, `Not` or `Refined` can often lead to a decrease in readability.
360+
361+
Directly writing `And`, `Or`, `Not` or `Refined` can often lead to a decrease in readability.
340362
Therefore, using **type aliases** can help make your code clearer.
341363

342364
```rust
@@ -346,6 +368,7 @@ type ContainsHelloAndWorld = Refined<ContainsHelloAndWorldRule>;
346368
```
347369

348370
# License
371+
349372
MIT License
350373

351374
Copyright (c) 2024 Tomoki Someya

0 commit comments

Comments
 (0)