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