1use fidl::encoding::{
6 ALLOC_ABSENT_U32, ALLOC_PRESENT_U32, Context, Decode, Decoder, DefaultFuchsiaResourceDialect,
7 Depth, Encode, Encoder, ResourceTypeMarker, TypeMarker,
8};
9
10use fdf::{Channel, MixedHandle, MixedHandleType};
11use zx::{HandleDisposition, HandleInfo, HandleOp, NullableHandle, ObjectType, Rights, Status};
12
13use std::marker::PhantomData;
14
15use crate::endpoints::DriverClientEnd;
16
17#[derive(Debug, Clone)]
18pub struct DriverEndpoint<T>(PhantomData<DriverClientEnd<T>>);
19
20unsafe impl<T: 'static> TypeMarker for DriverEndpoint<T> {
21 type Owned = DriverClientEnd<T>;
22
23 fn inline_align(_context: Context) -> usize {
24 4
25 }
26
27 fn inline_size(_context: Context) -> usize {
28 4
29 }
30}
31
32impl<T: 'static> ResourceTypeMarker for DriverEndpoint<T> {
33 type Borrowed<'a> = DriverClientEnd<T>;
34
35 fn take_or_borrow(value: &mut Self::Owned) -> Self::Borrowed<'_> {
36 DriverClientEnd(value.0.take(), PhantomData)
37 }
38}
39
40impl<T: 'static> Decode<DriverEndpoint<T>, DefaultFuchsiaResourceDialect> for DriverClientEnd<T> {
41 fn new_empty() -> Self {
42 Self(None, PhantomData)
43 }
44
45 unsafe fn decode(
46 &mut self,
47 decoder: &mut Decoder<'_, DefaultFuchsiaResourceDialect>,
48 offset: usize,
49 _depth: Depth,
50 ) -> fidl::Result<()> {
51 match decoder.read_num::<u32>(offset) {
52 ALLOC_PRESENT_U32 => {}
53 ALLOC_ABSENT_U32 => return Err(fidl::Error::NotNullable),
54 _ => return Err(fidl::Error::InvalidPresenceIndicator),
55 }
56 let handle = decoder.take_next_handle(ObjectType::NONE, Rights::empty())?.into_raw();
59 let mixed_handle = unsafe { MixedHandle::try_from_raw(handle) };
60 match mixed_handle.map(MixedHandle::resolve) {
61 None => (),
62 Some(MixedHandleType::Driver(driver_handle)) => {
63 self.0 = unsafe { Some(Channel::from_driver_handle(driver_handle)) };
65 }
66 _ => {
67 return Err(fidl::Error::Invalid);
69 }
70 }
71 Ok(())
72 }
73}
74
75unsafe impl<T: 'static> Encode<DriverEndpoint<T>, DefaultFuchsiaResourceDialect>
76 for DriverClientEnd<T>
77{
78 unsafe fn encode(
79 self,
80 encoder: &mut Encoder<'_, DefaultFuchsiaResourceDialect>,
81 offset: usize,
82 _depth: Depth,
83 ) -> fidl::Result<()> {
84 let Some(channel) = self.0 else {
85 return Err(fidl::Error::NotNullable);
86 };
87 let handle = unsafe {
92 fidl::NullableHandle::from_raw(channel.into_driver_handle().into_raw().get())
93 };
94
95 unsafe { encoder.write_num(ALLOC_PRESENT_U32, offset) };
98 encoder.push_next_handle(HandleDisposition::new(
99 HandleOp::Move(handle),
100 ObjectType::NONE,
101 Rights::empty(),
102 Status::OK,
103 ));
104 Ok(())
105 }
106}
107
108pub unsafe fn mixed_into_handle_info(this: Option<MixedHandle>) -> Result<HandleInfo, Status> {
120 use MixedHandleType::*;
121 let Some(this) = this else {
122 return Ok(HandleInfo::new(NullableHandle::invalid(), ObjectType::NONE, Rights::empty()));
123 };
124 match this.resolve() {
125 Zircon(handle) => {
126 let basic_info = handle.basic_info()?;
127 Ok(HandleInfo::new(handle, basic_info.object_type, basic_info.rights))
128 }
129 Driver(handle) => {
130 Ok(HandleInfo::new(
133 unsafe { NullableHandle::from_raw(handle.into_raw().get()) },
134 ObjectType::NONE,
135 Rights::empty(),
136 ))
137 }
138 }
139}
140
141pub fn mixed_from_handle_disposition(
148 mut handle: HandleDisposition<'static>,
149) -> Option<MixedHandle> {
150 use zx::HandleOp::*;
151 match handle.take_op() {
152 Move(handle) => MixedHandle::from_zircon_handle(handle),
153 Duplicate(_) => {
154 panic!("tried to convert a duplicate HandleDisposition into a driver MixedHandle")
155 }
156 }
157}
158
159#[cfg(test)]
160mod tests {
161 use fdf::DriverHandle;
162 use zx::Port;
163
164 use super::*;
165
166 fn make_driver_handle() -> DriverHandle {
168 let (left, right) = fdf::Channel::<()>::create();
169 drop(right);
170 left.into_driver_handle()
171 }
172
173 #[test]
174 fn driver_handle_info() {
175 let handle = MixedHandle::from(make_driver_handle());
176 let handle_info = unsafe { mixed_into_handle_info(Some(handle)).unwrap() };
177 assert_eq!(handle_info.object_type, ObjectType::NONE);
178 assert_eq!(handle_info.rights, Rights::empty());
179 MixedHandle::from_zircon_handle(handle_info.handle).unwrap();
181 }
182
183 #[test]
184 fn driver_handle_disposition() {
185 let handle_disposition = HandleDisposition::new(
186 HandleOp::Move(unsafe {
187 NullableHandle::from_raw(make_driver_handle().into_raw().get())
188 }),
189 ObjectType::NONE,
190 Rights::empty(),
191 Status::OK,
192 );
193 mixed_from_handle_disposition(handle_disposition).unwrap();
194 }
195
196 #[test]
197 fn zircon_handle_info() {
198 let handle = MixedHandle::from_zircon_handle(Port::create().into()).unwrap();
199 let handle_info = unsafe { mixed_into_handle_info(Some(handle)).unwrap() };
200 assert_eq!(handle_info.object_type, ObjectType::PORT);
201 assert_eq!(
202 handle_info.rights,
203 Rights::DUPLICATE | Rights::TRANSFER | Rights::READ | Rights::WRITE | Rights::INSPECT
204 );
205 MixedHandle::from_zircon_handle(handle_info.handle).unwrap();
207 }
208
209 #[test]
210 fn zircon_handle_disposition() {
211 let handle_disposition = HandleDisposition::new(
212 HandleOp::Move(Port::create().into()),
213 ObjectType::PORT,
214 Rights::DUPLICATE | Rights::TRANSFER | Rights::READ | Rights::WRITE | Rights::INSPECT,
215 Status::OK,
216 );
217 mixed_from_handle_disposition(handle_disposition).unwrap();
218 }
219}