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