Skip to main content

stdbind/
optional.rs

1// Copyright 2026 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5/// An ABI-stable adapter for `Option<T>` designed for FFI bindings that use
6/// the C++ `stdbind::optional<T>`.
7#[derive(Clone, Copy, Debug, Eq, PartialEq)]
8#[repr(u64)]
9pub enum Optional<T> {
10    None,
11    Some(T),
12}
13
14impl<T> From<Option<T>> for Optional<T> {
15    #[inline]
16    fn from(opt: Option<T>) -> Self {
17        match opt {
18            Some(val) => Optional::Some(val),
19            None => Optional::None,
20        }
21    }
22}
23
24impl<T> From<Optional<T>> for Option<T> {
25    #[inline]
26    fn from(opt: Optional<T>) -> Self {
27        match opt {
28            Optional::Some(val) => Some(val),
29            Optional::None => None,
30        }
31    }
32}
33
34#[cfg(test)]
35mod tests {
36    use super::*;
37
38    #[test]
39    fn test_conversions() {
40        let std_opt = Some(123u64);
41        let stdbind_opt: Optional<u64> = std_opt.into();
42        assert_eq!(stdbind_opt, Optional::Some(123));
43
44        let back_to_std: Option<u64> = stdbind_opt.into();
45        assert_eq!(back_to_std, Some(123));
46
47        let none_std: Option<u64> = None;
48        let none_stdbind: Optional<u64> = none_std.into();
49        assert_eq!(none_stdbind, Optional::None);
50
51        let back_to_none: Option<u64> = none_stdbind.into();
52        assert_eq!(back_to_none, None);
53    }
54
55    #[derive(Clone, Copy, Debug, Eq, PartialEq)]
56    #[repr(C)]
57    struct Point {
58        x: i32,
59        y: i32,
60    }
61
62    #[test]
63    fn test_layouts() {
64        assert_eq!(size_of::<Optional<u8>>(), 16);
65        assert_eq!(align_of::<Optional<u8>>(), 8);
66
67        assert_eq!(size_of::<Optional<u16>>(), 16);
68        assert_eq!(align_of::<Optional<u16>>(), 8);
69
70        assert_eq!(size_of::<Optional<u32>>(), 16);
71        assert_eq!(align_of::<Optional<u32>>(), 8);
72
73        assert_eq!(size_of::<Optional<u64>>(), 16);
74        assert_eq!(align_of::<Optional<u64>>(), 8);
75
76        assert_eq!(size_of::<Optional<Point>>(), 16);
77        assert_eq!(align_of::<Optional<Point>>(), 8);
78    }
79
80    #[test]
81    fn test_discriminants() {
82        let none: Optional<u32> = Optional::None;
83        assert_eq!(unsafe { *(core::ptr::addr_of!(none) as *const u64) }, 0);
84
85        let some: Optional<u32> = Optional::Some(0x12345678);
86        assert_eq!(unsafe { *(core::ptr::addr_of!(some) as *const u64) }, 1);
87        assert_eq!(
88            unsafe { *((core::ptr::addr_of!(some) as *const u8).add(8) as *const u32) },
89            0x12345678
90        );
91    }
92}