1use cubecl_macros::derive_expand;
2
3use crate as cubecl;
4use crate::prelude::*;
5
6#[derive_expand(CubeType, CubeTypeMut, IntoRuntime)]
7#[cube(runtime_variants, no_constructors)]
8pub enum Option<T: CubeType> {
9 None,
11 Some(T),
13}
14
15fn discriminant(variant_name: &'static str) -> i32 {
16 OptionExpand::<u32>::discriminant_of(variant_name)
17}
18
19pub enum OptionArgs<T: LaunchArg, R: Runtime> {
20 Some(<T as LaunchArg>::RuntimeArg<R>),
21 None,
22}
23
24impl<T: LaunchArg, R: Runtime> From<Option<<T as LaunchArg>::RuntimeArg<R>>> for OptionArgs<T, R> {
25 fn from(value: Option<<T as LaunchArg>::RuntimeArg<R>>) -> Self {
26 match value {
27 Some(arg) => Self::Some(arg),
28 None => Self::None,
29 }
30 }
31}
32
33impl<T: LaunchArg + CubeType + Default + IntoRuntime + 'static> LaunchArg for Option<T> {
34 type RuntimeArg<R: Runtime> = OptionArgs<T, R>;
35 type CompilationArg = OptionCompilationArg<T>;
36
37 fn register<R: Runtime>(
38 arg: Self::RuntimeArg<R>,
39 launcher: &mut KernelLauncher<R>,
40 ) -> Self::CompilationArg {
41 match arg {
42 OptionArgs::Some(arg) => OptionCompilationArg::Some(T::register(arg, launcher)),
43 OptionArgs::None => OptionCompilationArg::None,
44 }
45 }
46
47 fn expand(
48 arg: &Self::CompilationArg,
49 builder: &mut KernelBuilder,
50 ) -> <Self as CubeType>::ExpandType {
51 match arg {
52 OptionCompilationArg::Some(value) => {
53 let value = T::expand(value, builder);
54 OptionExpand {
55 discriminant: discriminant("Some").into(),
56 value,
57 }
58 }
59 OptionCompilationArg::None => OptionExpand {
60 discriminant: discriminant("None").into(),
61 value: T::default().__expand_runtime_method(&builder.scope),
62 },
63 }
64 }
65}
66
67pub enum OptionCompilationArg<T: LaunchArg> {
68 Some(T::CompilationArg),
69 None,
70}
71
72impl<T: LaunchArg> Clone for OptionCompilationArg<T> {
73 fn clone(&self) -> Self {
74 match self {
75 OptionCompilationArg::Some(value) => OptionCompilationArg::Some(value.clone()),
76 OptionCompilationArg::None => OptionCompilationArg::None,
77 }
78 }
79}
80
81impl<T: LaunchArg> PartialEq for OptionCompilationArg<T> {
82 fn eq(&self, other: &Self) -> bool {
83 match (self, other) {
84 (Self::Some(l0), Self::Some(r0)) => l0 == r0,
85 _ => core::mem::discriminant(self) == core::mem::discriminant(other),
86 }
87 }
88}
89
90impl<T: LaunchArg> Eq for OptionCompilationArg<T> {}
91
92impl<T: LaunchArg> core::hash::Hash for OptionCompilationArg<T> {
93 fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
94 core::mem::discriminant(self).hash(state);
95 match self {
96 OptionCompilationArg::Some(value) => value.hash(state),
97 OptionCompilationArg::None => {}
98 }
99 }
100}
101
102impl<T: LaunchArg> core::fmt::Debug for OptionCompilationArg<T> {
103 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
104 match self {
105 Self::Some(arg0) => f.debug_tuple("Some").field(arg0).finish(),
106 Self::None => write!(f, "None"),
107 }
108 }
109}
110
111#[allow(non_snake_case)]
113pub trait CubeOption<T: CubeType> {
114 fn new_Some(_0: T) -> Option<T> {
116 Option::Some(_0)
117 }
118 fn none_with_default(_0: T) -> Option<T> {
119 Option::None
120 }
121
122 #[doc(hidden)]
123 fn __expand_Some(scope: &Scope, value: T::ExpandType) -> OptionExpand<T> {
124 Self::__expand_new_Some(scope, value)
125 }
126 #[doc(hidden)]
127 fn __expand_new_Some(_scope: &Scope, value: T::ExpandType) -> OptionExpand<T> {
128 OptionExpand::<T> {
129 discriminant: discriminant("Some").into(),
130 value,
131 }
132 }
133 fn __expand_none_with_default(_scope: &Scope, value: T::ExpandType) -> OptionExpand<T> {
134 OptionExpand {
135 discriminant: discriminant("None").into(),
136 value,
137 }
138 }
139}
140
141#[allow(non_snake_case)]
143pub trait CubeOptionDefault<T: CubeType + Default + IntoRuntime>: CubeOption<T> {
144 fn new_None() -> Option<T> {
146 Option::None
147 }
148
149 #[doc(hidden)]
150 fn __expand_new_None(scope: &Scope) -> OptionExpand<T> {
151 let value = T::default().__expand_runtime_method(scope);
152 Self::__expand_none_with_default(scope, value)
153 }
154}
155
156impl<T: CubeType> CubeOption<T> for Option<T> {}
157impl<T: CubeType + Default + IntoRuntime> CubeOptionDefault<T> for Option<T> {}
158
159mod impls {
160 use core::ops::{Deref, DerefMut};
161
162 use super::*;
163 use crate as cubecl;
164
165 #[doc(hidden)]
170 impl<T: CubeType> OptionExpand<T> {
171 pub fn __expand_is_some_method(&self, scope: &Scope) -> NativeExpand<bool> {
172 self.discriminant
173 .__expand_eq_method(scope, &discriminant("Some").into())
174 }
175
176 pub fn __expand_is_some_and_method(
177 self,
178 scope: &Scope,
179 f: impl FnOnce(&Scope, T::ExpandType) -> NativeExpand<bool>,
180 ) -> NativeExpand<bool> {
181 match_expand_expr(scope, self, discriminant("None"), |_, _| false)
182 .case(scope, discriminant("Some"), |scope, value| f(scope, value))
183 .finish(scope)
184 }
185
186 pub fn __expand_is_none_or_method(
187 self,
188 scope: &Scope,
189 f: impl FnOnce(&Scope, T::ExpandType) -> NativeExpand<bool>,
190 ) -> NativeExpand<bool> {
191 match_expand_expr(scope, self, discriminant("None"), |_, _| true)
192 .case(scope, discriminant("Some"), |scope, value| f(scope, value))
193 .finish(scope)
194 }
195
196 pub fn __expand_expect_method(self, scope: &Scope, msg: &str) -> T::ExpandType
197 where
198 T::ExpandType: RuntimeAssign,
199 {
200 match_expand_expr(scope, self, discriminant("Some"), |_, value| value)
202 .case(scope, discriminant("None"), |scope, value| {
203 printf_expand(scope, msg, alloc::vec![]);
204 terminate!();
205 value
206 })
207 .finish(scope)
208 }
209
210 pub fn __expand_unwrap_or_else_method<F>(self, scope: &Scope, f: F) -> T::ExpandType
211 where
212 F: FnOnce(&Scope) -> T::ExpandType,
213 T::ExpandType: RuntimeAssign,
214 {
215 match_expand_expr(scope, self, discriminant("Some"), |_, value| value)
216 .case(scope, discriminant("None"), |scope, _| f(scope))
217 .finish(scope)
218 }
219
220 pub fn __expand_map_method<U, F>(self, scope: &Scope, f: F) -> OptionExpand<U>
221 where
222 F: FnOnce(&Scope, T::ExpandType) -> U::ExpandType,
223 U: CubeType + IntoRuntime + Default,
224 OptionExpand<U>: RuntimeAssign<Expand = OptionExpand<U>>,
225 {
226 match_expand_expr(scope, self, discriminant("Some"), |scope, value| {
227 let value = f(scope, value);
228 Option::__expand_new_Some(scope, value)
229 })
230 .case(scope, discriminant("None"), |scope, _| {
231 Option::__expand_new_None(scope)
232 })
233 .finish(scope)
234 }
235
236 pub fn __expand_inspect_method<F>(self, scope: &Scope, f: F) -> Self
237 where
238 F: FnOnce(&Scope, &T::ExpandType),
239 {
240 match_expand(
241 scope,
242 self.clone_unchecked(),
243 discriminant("Some"),
244 |scope, value| f(scope, &value),
245 )
246 .case(scope, discriminant("None"), |_, _| {})
247 .finish(scope);
248 self
249 }
250
251 pub fn __expand_map_or_method<U, F>(
252 self,
253 scope: &Scope,
254 default: U::ExpandType,
255 f: F,
256 ) -> U::ExpandType
257 where
258 F: FnOnce(&Scope, T::ExpandType) -> U::ExpandType,
259 U: CubeType + Default + IntoRuntime,
260 U::ExpandType: RuntimeAssign,
261 {
262 match_expand_expr(scope, self, discriminant("Some"), f)
263 .case(scope, discriminant("None"), |_, _| default)
264 .finish(scope)
265 }
266
267 pub fn __expand_map_or_else_method<U, D, F>(
268 self,
269 scope: &Scope,
270 default: D,
271 f: F,
272 ) -> U::ExpandType
273 where
274 D: FnOnce(&Scope) -> U::ExpandType,
275 F: FnOnce(&Scope, T::ExpandType) -> U::ExpandType,
276 U: CubeType + Default + IntoRuntime,
277 U::ExpandType: RuntimeAssign,
278 {
279 match_expand_expr(scope, self, discriminant("Some"), f)
280 .case(scope, discriminant("None"), |scope, _| default(scope))
281 .finish(scope)
282 }
283
284 pub fn __expand_map_or_default_method<U, F>(self, scope: &Scope, f: F) -> U::ExpandType
285 where
286 U: CubeType + IntoRuntime + Default,
287 F: FnOnce(&Scope, T::ExpandType) -> U::ExpandType,
288 U::ExpandType: RuntimeAssign,
289 {
290 match_expand_expr(scope, self, discriminant("Some"), f)
291 .case(scope, discriminant("None"), |scope, _| {
292 U::default().__expand_runtime_method(scope)
293 })
294 .finish(scope)
295 }
296
297 pub fn __expand_as_deref_method(self, scope: &Scope) -> OptionExpand<T::Target>
298 where
299 T: Deref<Target: CubeType + Default + IntoRuntime>,
300 T::ExpandType: DerefExpand<Target = <T::Target as CubeType>::ExpandType>,
301 <T::Target as CubeType>::ExpandType: RuntimeAssign,
302 {
303 self.__expand_map_method(scope, |scope, value| value.__expand_deref_method(scope))
304 }
305
306 pub fn __expand_as_deref_mut_method(self, scope: &Scope) -> OptionExpand<T::Target>
307 where
308 T: DerefMut<Target: CubeType + Default + IntoRuntime>,
309 T::ExpandType: DerefExpand<Target = <T::Target as CubeType>::ExpandType>,
310 <T::Target as CubeType>::ExpandType: RuntimeAssign,
311 {
312 self.__expand_map_method(scope, |scope, value| value.__expand_deref_method(scope))
313 }
314
315 pub fn __expand_and_then_method<U, F>(self, scope: &Scope, f: F) -> OptionExpand<U>
316 where
317 F: FnOnce(&Scope, T::ExpandType) -> OptionExpand<U>,
318 U: CubeType + IntoRuntime + Default,
319 U::ExpandType: RuntimeAssign,
320 {
321 match_expand_expr(scope, self, discriminant("Some"), f)
322 .case(scope, discriminant("None"), |scope, _| {
323 Option::__expand_new_None(scope)
324 })
325 .finish(scope)
326 }
327
328 pub fn __expand_filter_method<P>(self, scope: &Scope, predicate: P) -> Self
329 where
330 P: FnOnce(&Scope, &T::ExpandType) -> NativeExpand<bool>,
331 T: Default + IntoRuntime,
332 Self: RuntimeAssign + IntoExpand<Expand = Self>,
333 {
334 match_expand_expr(scope, self, discriminant("Some"), |scope, value| {
335 let cond = predicate(scope, &value);
336 if_else_expr_expand(scope, cond, |scope| Option::__expand_new_Some(scope, value))
337 .or_else(scope, |scope| Option::__expand_new_None(scope))
338 })
339 .case(scope, discriminant("None"), |scope, _| {
340 Option::__expand_new_None(scope)
341 })
342 .finish(scope)
343 }
344
345 pub fn __expand_or_else_method<F>(self, scope: &Scope, f: F) -> OptionExpand<T>
346 where
347 F: FnOnce(&Scope) -> OptionExpand<T>,
348 OptionExpand<T>: RuntimeAssign + IntoExpand<Expand = OptionExpand<T>>,
349 {
350 let is_some = self.__expand_is_some_method(scope);
351 if_else_expr_expand(scope, is_some, |_| self).or_else(scope, |scope| f(scope))
352 }
353
354 pub fn __expand_zip_with_method<U, F, R>(
355 self,
356 scope: &Scope,
357 other: OptionExpand<U>,
358 f: F,
359 ) -> OptionExpand<R>
360 where
361 F: FnOnce(&Scope, T::ExpandType, U::ExpandType) -> R::ExpandType,
362 U: CubeType,
363 R: CubeType + IntoRuntime + Default,
364 OptionExpand<R>: RuntimeAssign + IntoExpand<Expand = OptionExpand<R>>,
365 {
366 match_expand_expr(scope, self, discriminant("Some"), |scope, value| {
367 match_expand_expr(scope, other, discriminant("Some"), |scope, other| {
368 let value = f(scope, value, other);
369 Option::__expand_new_Some(scope, value)
370 })
371 .case(scope, discriminant("None"), |scope, _| {
372 Option::__expand_new_None(scope)
373 })
374 .finish(scope)
375 })
376 .case(scope, discriminant("None"), |scope, _| {
377 Option::__expand_new_None(scope)
378 })
379 .finish(scope)
380 }
381
382 pub fn __expand_reduce_method<U, R, F>(
383 self,
384 scope: &Scope,
385 other: OptionExpand<U>,
386 f: F,
387 ) -> OptionExpand<R>
388 where
389 T::ExpandType: Into<R::ExpandType>,
390 U::ExpandType: Into<R::ExpandType>,
391 F: FnOnce(&Scope, T::ExpandType, U::ExpandType) -> R::ExpandType,
392 U: CubeType + IntoRuntime + Default,
393 R: CubeType + IntoRuntime + Default,
394 OptionExpand<R>: RuntimeAssign + IntoExpand<Expand = OptionExpand<R>>,
395 {
396 match_expand_expr(scope, self, discriminant("Some"), {
397 let other = other.clone_unchecked();
398 |scope, value| {
399 match_expand_expr(scope, other, discriminant("Some"), {
400 let value = value.clone_unchecked();
401 |scope, other| {
402 let value = f(scope, value, other);
403 Option::__expand_new_Some(scope, value)
404 }
405 })
406 .case(scope, discriminant("None"), |scope, _| {
407 Option::__expand_new_Some(scope, value.into())
408 })
409 .finish(scope)
410 }
411 })
412 .case(scope, discriminant("None"), |scope, _| {
413 match_expand_expr(scope, other, discriminant("Some"), |scope, other| {
414 Option::__expand_new_Some(scope, other.into())
415 })
416 .case(scope, discriminant("None"), |scope, _| {
417 Option::__expand_new_None(scope)
418 })
419 .finish(scope)
420 })
421 .finish(scope)
422 }
423
424 #[allow(clippy::missing_safety_doc)]
425 pub unsafe fn __expand_unwrap_unchecked_method(self, scope: &Scope) -> T::ExpandType
426 where
427 T::ExpandType: RuntimeAssign,
428 {
429 match_expand_expr(scope, self, discriminant("Some"), |_, value| value).finish(scope)
430 }
431 }
432
433 #[cube(expand_only)]
434 impl<T: CubeType> Option<T> {
435 #[must_use = "if you intended to assert that this doesn't have a value, consider \
447 wrapping this in an `assert!()` instead"]
448 pub fn is_none(&self) -> bool {
449 !self.is_some()
450 }
451
452 pub fn unwrap(self) -> T
489 where
490 T::ExpandType: RuntimeAssign,
491 {
492 self.expect("called `Option::unwrap()` on a `None` value")
493 }
494
495 pub fn unwrap_or(self, default: T) -> T
510 where
511 T::ExpandType: RuntimeAssign,
512 {
513 match self {
514 Some(x) => x,
515 None => default,
516 }
517 }
518
519 pub fn unwrap_or_default(self) -> T
539 where
540 T: Default + IntoRuntime,
541 T::ExpandType: RuntimeAssign,
542 {
543 match self {
544 Some(x) => x,
545 None => comptime![T::default()].runtime(),
546 }
547 }
548
549 pub fn and<U>(self, optb: Option<U>) -> Option<U>
585 where
586 U: CubeType + IntoRuntime + Default,
587 U::ExpandType: RuntimeAssign,
588 {
589 match self {
590 Option::Some(_) => optb,
591 Option::None => Option::new_None(),
592 }
593 }
594
595 pub fn or(self, optb: Option<T>) -> Option<T>
623 where
624 T::ExpandType: RuntimeAssign,
625 {
626 if self.is_some() { self } else { optb }
627 }
628
629 pub fn xor(self, optb: Option<T>) -> Option<T>
651 where
652 T: Default + IntoRuntime,
653 T::ExpandType: RuntimeAssign,
654 {
655 let this_is_none = self.is_none();
656
657 if self.is_some() && optb.is_none() {
658 self
659 } else if this_is_none && optb.is_some() {
660 optb
661 } else {
662 Option::new_None()
663 }
664 }
665
666 pub fn zip<U>(self, other: Option<U>) -> Option<(T, U)>
688 where
689 U: CubeType,
690 (T, U): Default + CubeType + IntoRuntime,
691 (T::ExpandType, U::ExpandType): Into<<(T, U) as CubeType>::ExpandType>,
692 OptionExpand<(T, U)>: RuntimeAssign + IntoExpand<Expand = OptionExpand<(T, U)>>,
693 {
694 match self {
695 Some(a) => match other {
696 Some(b) => Option::Some((a, b)),
697 None => Option::new_None(),
698 },
699 None => Option::new_None(),
700 }
701 }
702 }
703
704 #[cube(expand_only)]
705 impl<
706 T: CubeType<ExpandType: RuntimeAssign> + IntoRuntime + Default,
707 U: CubeType<ExpandType: RuntimeAssign> + IntoRuntime + Default,
708 > Option<(T, U)>
709 {
710 #[inline]
725 pub fn unzip(self) -> (Option<T>, Option<U>) {
726 match self {
727 Option::Some(value) => (Option::Some(value.0), Option::Some(value.1)),
728 Option::None => (Option::new_None(), Option::new_None()),
729 }
730 }
731 }
732}