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}