moveit/new/factories.rs
1// Copyright 2021 Google LLC
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use core::convert::TryFrom;
16use core::convert::TryInto;
17use core::marker::PhantomData;
18use core::mem::MaybeUninit;
19use core::pin::Pin;
20
21use crate::new::New;
22use crate::new::TryNew;
23
24/// Returns a [`New`] that uses the provided closure for construction.
25///
26/// This is the most primitive [`New`]-creation function, and is almost-always
27/// preferred over implementing [`New`] directly.
28///
29/// # Safety
30///
31/// `f` must respect the safety requirements of [`New`], since it is used
32/// as an implementation basis.
33#[inline]
34pub unsafe fn by_raw<T, F>(f: F) -> impl New<Output = T>
35where
36 F: FnOnce(Pin<&mut MaybeUninit<T>>),
37{
38 struct FnNew<F, T> {
39 f: F,
40 _ph: PhantomData<fn(T)>,
41 }
42
43 unsafe impl<F, T> New for FnNew<F, T>
44 where
45 F: FnOnce(Pin<&mut MaybeUninit<T>>),
46 {
47 type Output = T;
48 #[inline]
49 unsafe fn new(self, this: Pin<&mut MaybeUninit<Self::Output>>) {
50 (self.f)(this)
51 }
52 }
53
54 FnNew::<F, T> {
55 f,
56 _ph: PhantomData,
57 }
58}
59
60/// Returns a [`New`] that uses the provided closure for constructing a
61/// `T`.
62///
63/// ```
64/// # use moveit::{moveit, new};
65/// moveit! {
66/// let x = new::by(|| 21 * 2);
67/// }
68/// assert_eq!(*x, 42);
69/// ```
70#[inline]
71pub fn by<T, F>(f: F) -> impl New<Output = T>
72where
73 F: FnOnce() -> T,
74{
75 unsafe { by_raw(|mut this| this.set(MaybeUninit::new(f()))) }
76}
77
78/// Returns a [`New`] that uses a [`From`] implementation to generate a `T`.
79///
80/// ```
81/// # use std::pin::Pin;
82/// # use moveit::{moveit, new, MoveRef};
83/// moveit! {
84/// let x: Pin<MoveRef<String>> = new::from("foo");
85/// }
86/// assert_eq!(*x, "foo");
87/// ```
88#[inline]
89pub fn from<T: From<U>, U>(val: U) -> impl New<Output = T> {
90 by(|| val.into())
91}
92
93/// Returns a [`New`] that simply returns the given value.
94///
95/// ```
96/// # use std::pin::Pin;
97/// # use moveit::{moveit, new};
98/// moveit! {
99/// let x = new::of(42);
100/// }
101/// assert_eq!(*x, 42);
102/// ```
103///
104/// In general, you will almost always want [`from()`].
105#[inline]
106pub fn of<T>(val: T) -> impl New<Output = T> {
107 by(|| val)
108}
109
110/// Returns a [`New`] calls [`Default`] to generate a `T`.
111///
112/// ```
113/// # use std::pin::Pin;
114/// # use moveit::{moveit, new};
115/// moveit! {
116/// let x = new::default::<i32>();
117/// }
118/// assert_eq!(*x, 0);
119/// ```
120#[inline]
121pub fn default<T: Default>() -> impl New<Output = T> {
122 by(Default::default)
123}
124
125/// Returns a [`TryNew`] that uses the provided closure for construction.
126///
127/// This is the most primitive [`TryNew`]-creation function, and is
128/// almost-always preferred over implementing [`TryNew`] directly.
129///
130/// # Safety
131///
132/// `f` must respect the safety requirements of [`TryNew`], since it is used
133/// as an implementation basis.
134#[inline]
135pub unsafe fn try_by_raw<T, E, F>(f: F) -> impl TryNew<Output = T, Error = E>
136where
137 F: FnOnce(Pin<&mut MaybeUninit<T>>) -> Result<(), E>,
138{
139 struct FnNew<F, T, E> {
140 f: F,
141 _ph: PhantomData<fn(T) -> E>,
142 }
143
144 unsafe impl<F, T, E> TryNew for FnNew<F, T, E>
145 where
146 F: FnOnce(Pin<&mut MaybeUninit<T>>) -> Result<(), E>,
147 {
148 type Output = T;
149 type Error = E;
150 #[inline]
151 unsafe fn try_new(
152 self,
153 this: Pin<&mut MaybeUninit<Self::Output>>,
154 ) -> Result<(), E> {
155 (self.f)(this)
156 }
157 }
158
159 FnNew::<F, T, E> {
160 f,
161 _ph: PhantomData,
162 }
163}
164
165/// Returns a [`TryNew`] that uses the provided closure for constructing a
166/// `T`.
167#[inline]
168pub fn try_by<T, E, F>(f: F) -> impl TryNew<Output = T, Error = E>
169where
170 F: FnOnce() -> Result<T, E>,
171{
172 unsafe {
173 try_by_raw(|this| {
174 this.get_unchecked_mut().write(f()?);
175 Ok(())
176 })
177 }
178}
179
180/// Returns a [`TryNew`] that uses a `TryFrom` implementation to generate a `T`.
181#[inline]
182pub fn try_from<T: TryFrom<U>, U>(
183 val: U,
184) -> impl TryNew<Output = T, Error = T::Error> {
185 try_by(|| val.try_into())
186}