starnix_types/
convert.rs

1// Copyright 2024 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
5use starnix_uapi::open_flags::OpenFlags;
6use {fidl_fuchsia_io as fio, fidl_fuchsia_starnix_binder as fbinder};
7
8pub trait FromFidl<T>: Sized {
9    fn from_fidl(value: T) -> Self;
10}
11
12pub trait IntoFidl<T>: Sized {
13    // Required method
14    fn into_fidl(self) -> T;
15}
16
17impl<T, U> IntoFidl<U> for T
18where
19    U: FromFidl<T>,
20{
21    fn into_fidl(self) -> U {
22        U::from_fidl(self)
23    }
24}
25
26impl FromFidl<fio::OpenFlags> for OpenFlags {
27    fn from_fidl(fio_flags: fio::OpenFlags) -> Self {
28        let mut result = if fio_flags.contains(fio::OpenFlags::RIGHT_WRITABLE) {
29            if fio_flags.contains(fio::OpenFlags::RIGHT_READABLE) {
30                OpenFlags::RDWR
31            } else {
32                OpenFlags::WRONLY
33            }
34        } else {
35            OpenFlags::RDONLY
36        };
37        if fio_flags.contains(fio::OpenFlags::CREATE) {
38            result |= OpenFlags::CREAT;
39        }
40        if fio_flags.contains(fio::OpenFlags::CREATE_IF_ABSENT) {
41            result |= OpenFlags::EXCL;
42        }
43        if fio_flags.contains(fio::OpenFlags::TRUNCATE) {
44            result |= OpenFlags::TRUNC;
45        }
46        if fio_flags.contains(fio::OpenFlags::APPEND) {
47            result |= OpenFlags::APPEND;
48        }
49        if fio_flags.contains(fio::OpenFlags::DIRECTORY) {
50            result |= OpenFlags::DIRECTORY;
51        }
52        result
53    }
54}
55
56impl FromFidl<OpenFlags> for fio::OpenFlags {
57    fn from_fidl(flags: OpenFlags) -> fio::OpenFlags {
58        let mut result = fio::OpenFlags::empty();
59        if flags.can_read() {
60            result |= fio::OpenFlags::RIGHT_READABLE | fio::OpenFlags::POSIX_WRITABLE;
61        }
62        if flags.can_write() {
63            result |= fio::OpenFlags::RIGHT_WRITABLE;
64        }
65        if flags.contains(OpenFlags::CREAT) {
66            result |= fio::OpenFlags::CREATE;
67        }
68        if flags.contains(OpenFlags::EXCL) {
69            result |= fio::OpenFlags::CREATE_IF_ABSENT;
70        }
71        if flags.contains(OpenFlags::TRUNC) {
72            result |= fio::OpenFlags::TRUNCATE;
73        }
74        if flags.contains(OpenFlags::APPEND) {
75            result |= fio::OpenFlags::APPEND;
76        }
77        if flags.contains(OpenFlags::DIRECTORY) {
78            result |= fio::OpenFlags::DIRECTORY;
79        }
80        result
81    }
82}
83
84impl FromFidl<OpenFlags> for fbinder::FileFlags {
85    fn from_fidl(flags: OpenFlags) -> Self {
86        let mut result = Self::empty();
87        if flags.can_read() {
88            result |= Self::RIGHT_READABLE;
89        }
90        if flags.can_write() {
91            result |= Self::RIGHT_WRITABLE;
92        }
93        if flags.contains(OpenFlags::DIRECTORY) {
94            result |= Self::DIRECTORY;
95        }
96
97        result
98    }
99}
100
101impl FromFidl<fbinder::FileFlags> for OpenFlags {
102    fn from_fidl(flags: fbinder::FileFlags) -> Self {
103        let readable = flags.contains(fbinder::FileFlags::RIGHT_READABLE);
104        let writable = flags.contains(fbinder::FileFlags::RIGHT_WRITABLE);
105        let mut result = Self::empty();
106        if readable && writable {
107            result = Self::RDWR;
108        } else if writable {
109            result = Self::WRONLY;
110        } else if readable {
111            result = Self::RDONLY;
112        }
113        if flags.contains(fbinder::FileFlags::DIRECTORY) {
114            result |= Self::DIRECTORY;
115        }
116        result
117    }
118}
119
120#[cfg(test)]
121mod tests {
122    use super::*;
123    use starnix_uapi::uapi;
124
125    fn assert_flags_equals(flags: OpenFlags, fio_flags: fio::OpenFlags) {
126        assert_eq!(flags, fio_flags.into_fidl());
127        assert_eq!(fio_flags, flags.into_fidl());
128    }
129
130    #[::fuchsia::test]
131    fn test_access() {
132        let read_only = OpenFlags::from_bits_truncate(uapi::O_RDONLY);
133        assert!(read_only.can_read());
134        assert!(!read_only.can_write());
135
136        let write_only = OpenFlags::from_bits_truncate(uapi::O_WRONLY);
137        assert!(!write_only.can_read());
138        assert!(write_only.can_write());
139
140        let read_write = OpenFlags::from_bits_truncate(uapi::O_RDWR);
141        assert!(read_write.can_read());
142        assert!(read_write.can_write());
143    }
144
145    #[::fuchsia::test]
146    fn test_conversion() {
147        assert_flags_equals(
148            OpenFlags::RDONLY,
149            fio::OpenFlags::RIGHT_READABLE | fio::OpenFlags::POSIX_WRITABLE,
150        );
151        assert_flags_equals(OpenFlags::WRONLY, fio::OpenFlags::RIGHT_WRITABLE);
152        assert_flags_equals(
153            OpenFlags::RDWR,
154            fio::OpenFlags::RIGHT_READABLE
155                | fio::OpenFlags::RIGHT_WRITABLE
156                | fio::OpenFlags::POSIX_WRITABLE,
157        );
158    }
159}