std_reset/traits/of_to/
mod.rs

1//! Трейты для преобразования типов.
2//! 
3//! Трейты  [`Of`]/[`To`] являются заменой [`From`]/[`Into`] из стандартной библиотеки и имеют более функциональный вид.
4//!
5//! Данная реализация [`From`]/[`Into`] может быть полензна, когда мы хотим сохранить функциональный стиль, при том что у нашего типа есть множество реализаций трейта [`From`].
6//!
7//! # Стандартная реализация с [`From`]/[`Into`]
8//! Когда у типа `TypeInto` появляется более одной реализации типажа [`From`], нам необходимо указать компилятору, какую из реализаций мы используем в данный момент.
9//! В стандартной реализации [`From`]/[`Into`]  это можно сделать с помощью следующих конструкций:
10//! - `<TypeFrom as Into<TypeInto>>::`
11//! - `Into::<TypeInto>>::`
12//! , где `TypeFrom` - тип, который укзан в реализации как `impl From<TypeFrom> for TypeInto`.
13//!
14//! ## Пример
15//! ```
16//! struct Rubles;
17//! struct Euros;
18//! struct Dollars;
19//! 
20//! impl From<Rubles> for Dollars {
21//!     fn from(value: Rubles) -> Self {
22//!         Dollars
23//!     }
24//! }
25//! 
26//! impl From<Euros> for Dollars {
27//!     fn from(value: Euros) -> Self {
28//!         Dollars
29//!     }
30//! }
31//! 
32//! fn from_into() {
33//!     let dollars = <Euros as Into<Dollars>>::into(Euros);
34//!     let dollars = Into::<Dollars>::into(Euros);
35//! }
36//! ```
37//!
38//! # Реализацис c [`Of`]/[`To`]
39//!
40//! Для того чтобы указать компилятору сигнатуру опрделеной реализации трейта, мы можем указать границы не только для самого трейта (высокий уровень), но и для функций этого трейта (низкий уровень).
41//! Так в трейте [`To`], generic типа, в который мы выполняем преобразование, указывается для метода `to`.
42//! Теперь, чтобы указать конкртеную реализацию, нам достаточно конретизировать метод трейта:
43//! - `TypeFrom.to::<TypeInto>()`
44//!
45//! ## Пример
46//! ```
47//! # use std_reset::prelude::{Of, To};
48//! #
49//! # struct Rubles;
50//! # struct Euros;
51//! # struct Dollars;
52//! #
53//! impl Of<Rubles> for Dollars {
54//!     fn of(value: Rubles) -> Self {
55//!         Dollars
56//!     }
57//! }
58//! 
59//! impl Of<Euros> for Dollars {
60//!     fn of(value: Euros) -> Self {
61//!         Dollars
62//!     }
63//! }
64//! 
65//! fn of_to() {
66//!     let dollars = Rubles.to::<Dollars>();
67//!     let dollars = Euros.to::<Dollars>();
68//! }
69//! ```
70pub trait Of<F, Output = Self>: To {
71    fn of(value: F) -> Output;
72}
73
74pub trait To {
75    fn to<I: Of<Self>>(self) -> I
76    where
77        Self: Sized;
78}
79
80impl<F> To for F {
81    fn to<I: Of<F>>(self) -> I {
82        I::of(self)
83    }
84}
85
86
87impl<F, I> Of<Vec<F>> for Vec<I>
88where
89    I: Of<F>,
90{
91    fn of(vec: Vec<F>) -> Self {
92        vec.into_iter().map(I::of).collect()
93    }
94}
95
96impl<F: Clone, I> Of<&Vec<F>> for Vec<I>
97where
98    I: Of<F>,
99{
100    fn of(vec: &Vec<F>) -> Self {
101        vec.into_iter().cloned().map(I::of).collect()
102    }
103}