OLD | NEW |
| (Empty) |
1 // Copyright 2016 The Chromium 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 use std::marker; | |
6 use std::mem; | |
7 use std::ops; | |
8 use std::ptr; | |
9 use std::slice; | |
10 use std::vec; | |
11 | |
12 use system::ffi; | |
13 // This full import is intentional; nearly every type in mojo_types needs to be
used. | |
14 use system::mojo_types::*; | |
15 use system::handle; | |
16 use system::handle::{CastHandle, Handle}; | |
17 | |
18 #[repr(u32)] | |
19 /// Create flags for data pipes | |
20 pub enum Create { | |
21 None = 0, | |
22 } | |
23 | |
24 #[repr(u32)] | |
25 /// Write flags for data pipes | |
26 pub enum Write { | |
27 None = 0, | |
28 | |
29 /// Write all the data to the pipe if possible or none at all | |
30 AllOrNone = 1 << 0, | |
31 } | |
32 | |
33 #[repr(u32)] | |
34 /// Read flags for data pipes | |
35 pub enum Read { | |
36 None = 0, | |
37 | |
38 /// Read all the data from the pipe if possible, or none at all | |
39 AllOrNone = 1 << 0, | |
40 | |
41 /// Dequeue the message recieved rather than reading it | |
42 Discard = 1 << 1, | |
43 | |
44 /// Get information about the queue on the pipe but do not perform the | |
45 /// read | |
46 Query = 1 << 2, | |
47 | |
48 /// Read data off the pipe's queue but do not dequeue it | |
49 Peek = 1 << 3, | |
50 } | |
51 | |
52 /// Intermediary structure in a two-phase read. | |
53 /// Reads of the requested buffer must be done directly | |
54 /// through this data structure which must then be committed. | |
55 pub struct ReadDataBuffer<'b, 'p, T> | |
56 where 'p: 'b, | |
57 T: 'p | |
58 { | |
59 buffer: &'b [T], | |
60 | |
61 /// Contains a reference to parent to end commit | |
62 /// and prevent it from outliving its parent handle. | |
63 parent: &'p Consumer<T>, | |
64 } | |
65 | |
66 impl<'b, 'p, T> ReadDataBuffer<'b, 'p, T> | |
67 where 'p: 'b, | |
68 T: 'p | |
69 { | |
70 /// Attempts to commit the read, that is, end the two-phase read | |
71 /// started by the parent Consumer<T> object. On a successful | |
72 /// commit, consumes self, otherwise returns self to try again. | |
73 pub fn commit(self, bytes_read: usize) -> Option<(Self, MojoResult)> { | |
74 let result = unsafe { self.parent.end_read(bytes_read) }; | |
75 if result == MojoResult::Okay { | |
76 None | |
77 } else { | |
78 Some((self, result)) | |
79 } | |
80 } | |
81 | |
82 /// Returns the length of the underlying buffer | |
83 pub fn len(&self) -> usize { | |
84 self.buffer.len() | |
85 } | |
86 } | |
87 | |
88 impl<'b, 'p, T> ops::Index<usize> for ReadDataBuffer<'b, 'p, T> | |
89 where 'p: 'b, | |
90 T: 'p | |
91 { | |
92 type Output = T; | |
93 | |
94 /// Overloads the indexing ([]) operator for reads. | |
95 /// | |
96 /// Part of reimplementing the array interface to be | |
97 /// able to use the structure naturally. | |
98 fn index(&self, index: usize) -> &T { | |
99 &self.buffer[index] | |
100 } | |
101 } | |
102 | |
103 /// Intermediary structure in a two-phase write. | |
104 /// Writes to the requested buffer must be done directly | |
105 /// through this data structure which must then be committed. | |
106 pub struct WriteDataBuffer<'b, 'p, T> | |
107 where 'p: 'b, | |
108 T: 'p | |
109 { | |
110 buffer: &'b mut [T], | |
111 | |
112 /// Contains a reference to parent to end commit | |
113 /// and prevent it from outliving its parent handle. | |
114 parent: &'p Producer<T>, | |
115 } | |
116 | |
117 impl<'b, 'p, T> WriteDataBuffer<'b, 'p, T> | |
118 where 'p: 'b, | |
119 T: 'p | |
120 { | |
121 /// Attempts to commit the write, that is, end the two-phase | |
122 /// write started by a Producer. On a successful | |
123 /// commit, consumes self, otherwise returns self to try again. | |
124 pub fn commit(self, bytes_written: usize) -> Option<(Self, MojoResult)> { | |
125 let result = unsafe { self.parent.end_write(bytes_written) }; | |
126 if result == MojoResult::Okay { | |
127 None | |
128 } else { | |
129 Some((self, result)) | |
130 } | |
131 } | |
132 | |
133 /// Returns the length of the underlying buffer | |
134 pub fn len(&self) -> usize { | |
135 self.buffer.len() | |
136 } | |
137 } | |
138 | |
139 impl<'b, 'p, T> ops::Index<usize> for WriteDataBuffer<'b, 'p, T> | |
140 where 'p: 'b, | |
141 T: 'p | |
142 { | |
143 type Output = T; | |
144 | |
145 /// Overloads the indexing ([]) operator for reads. | |
146 /// | |
147 /// Part of reimplementing the array interface to be | |
148 /// able to use the structure naturally. | |
149 fn index(&self, index: usize) -> &T { | |
150 &self.buffer[index] | |
151 } | |
152 } | |
153 | |
154 impl<'b, 'p, T> ops::IndexMut<usize> for WriteDataBuffer<'b, 'p, T> | |
155 where 'p: 'b, | |
156 T: 'p | |
157 { | |
158 /// Overloads the indexing ([]) operator for writes. | |
159 /// | |
160 /// Part of reimplementing the array interface to be | |
161 /// able to use the structure naturally. | |
162 fn index_mut(&mut self, index: usize) -> &mut T { | |
163 &mut self.buffer[index] | |
164 } | |
165 } | |
166 | |
167 /// Creates a data pipe, represented as a consumer | |
168 /// and a producer. Additionally, we associate a type | |
169 /// T with the data pipe, as data pipes operate in terms | |
170 /// of elements. In this way we can enforce type safety. | |
171 /// | |
172 /// Capacity, as an input, must be given in number of elements. | |
173 /// Use a capacity of 0 in order to use some system-dependent | |
174 /// default capacity. | |
175 pub fn create<T>(flags: CreateFlags, | |
176 capacity: u32) | |
177 -> Result<(Consumer<T>, Producer<T>), MojoResult> { | |
178 let elem_size = mem::size_of::<T>() as u32; | |
179 let opts = ffi::MojoCreateDataPipeOptions { | |
180 struct_size: mem::size_of::<ffi::MojoCreateDataPipeOptions>() as u32, | |
181 flags: flags, | |
182 element_num_bytes: elem_size, | |
183 capacity_num_bytes: capacity * elem_size, | |
184 _align: [], | |
185 }; | |
186 // TODO(mknyszek): Make sure handles are valid | |
187 let mut chandle: MojoHandle = 0; | |
188 let mut phandle: MojoHandle = 0; | |
189 let raw_opts = &opts as *const ffi::MojoCreateDataPipeOptions; | |
190 let r = MojoResult::from_code(unsafe { | |
191 ffi::MojoCreateDataPipe(raw_opts, | |
192 &mut phandle as *mut MojoHandle, | |
193 &mut chandle as *mut MojoHandle) | |
194 }); | |
195 if r != MojoResult::Okay { | |
196 Err(r) | |
197 } else { | |
198 Ok((Consumer::<T> { | |
199 handle: unsafe { handle::acquire(chandle) }, | |
200 _elem_type: marker::PhantomData, | |
201 }, | |
202 Producer::<T> { | |
203 handle: unsafe { handle::acquire(phandle) }, | |
204 _elem_type: marker::PhantomData, | |
205 })) | |
206 } | |
207 } | |
208 | |
209 /// Creates a data pipe, represented as a consumer | |
210 /// and a producer, using the default Mojo options. | |
211 pub fn create_default() -> Result<(Consumer<u8>, Producer<u8>), MojoResult> { | |
212 create::<u8>(Create::None as u32, 0) | |
213 } | |
214 | |
215 /// Represents the consumer half of a data pipe. | |
216 /// This data structure wraps a handle and acts | |
217 /// effectively as a typed handle. | |
218 /// | |
219 /// The purpose of the _elem_type field is to associate | |
220 /// a type with the consumer, as a data pipe works | |
221 /// in elements. | |
222 pub struct Consumer<T> { | |
223 handle: handle::UntypedHandle, | |
224 _elem_type: marker::PhantomData<T>, | |
225 } | |
226 | |
227 impl<T> Consumer<T> { | |
228 /// Perform a read operation on the consumer end of the data pipe. As | |
229 /// a result, we get an std::vec::Vec filled with whatever was written. | |
230 pub fn read(&self, flags: ReadFlags) -> Result<vec::Vec<T>, MojoResult> { | |
231 let mut num_bytes: u32 = 0; | |
232 let r_prelim = unsafe { | |
233 ffi::MojoReadData(self.handle.get_native_handle(), | |
234 ptr::null_mut() as *mut ffi::c_void, | |
235 &mut num_bytes as *mut u32, | |
236 1 << 2 as ReadFlags) | |
237 }; | |
238 if r_prelim != 0 || num_bytes == 0 { | |
239 return Err(MojoResult::from_code(r_prelim)); | |
240 } | |
241 let elem_size: u32 = mem::size_of::<T>() as u32; | |
242 // TODO(mknyszek): make sure elem_size divides into num_bytes | |
243 let mut buf: vec::Vec<T> = vec::Vec::with_capacity((num_bytes / elem_siz
e) as usize); | |
244 let r = MojoResult::from_code(unsafe { | |
245 ffi::MojoReadData(self.handle.get_native_handle(), | |
246 buf.as_mut_ptr() as *const ffi::c_void, | |
247 &mut num_bytes as *mut u32, | |
248 flags) | |
249 }); | |
250 unsafe { buf.set_len((num_bytes / elem_size) as usize) } | |
251 if r != MojoResult::Okay { | |
252 Err(r) | |
253 } else { | |
254 Ok(buf) | |
255 } | |
256 } | |
257 | |
258 /// Start two-phase read and return a ReadDataBuffer to perform | |
259 /// read and commit. | |
260 pub fn begin(&self, flags: ReadFlags) -> Result<ReadDataBuffer<T>, MojoResul
t> { | |
261 let wrapped_result = unsafe { self.begin_read(flags) }; | |
262 match wrapped_result { | |
263 Ok(arr) => { | |
264 Ok(ReadDataBuffer::<T> { | |
265 buffer: arr, | |
266 parent: self, | |
267 }) | |
268 } | |
269 Err(r) => Err(r), | |
270 } | |
271 } | |
272 | |
273 /// A private function that performs the first half of two-phase reading. | |
274 /// Kept private because it is unsafe to use (the array received may not | |
275 /// be valid if end_read is performed). | |
276 unsafe fn begin_read(&self, flags: ReadFlags) -> Result<&[T], MojoResult> { | |
277 let mut buf_num_bytes: u32 = 0; | |
278 let mut pbuf: *mut ffi::c_void = mem::uninitialized(); | |
279 let r = MojoResult::from_code(ffi::MojoBeginReadData(self.handle.get_nat
ive_handle(), | |
280 &mut pbuf, | |
281 &mut buf_num_bytes
as *mut u32, | |
282 flags)); | |
283 if r != MojoResult::Okay { | |
284 Err(r) | |
285 } else { | |
286 let buf_elems = (buf_num_bytes as usize) / mem::size_of::<T>(); | |
287 let buf = slice::from_raw_parts(pbuf as *mut T, buf_elems); | |
288 Ok(buf) | |
289 } | |
290 } | |
291 | |
292 /// A private function that performs the second half of two-phase reading. | |
293 /// Kept private because it is unsafe to use (the array received from start_
read | |
294 /// may not be valid if end_read is performed). | |
295 /// | |
296 /// Also assumes loads/stores aren't reordered such that a load/store may be | |
297 /// optimized to be run AFTER MojoEndReadData(). In general, this is true as
long | |
298 /// as raw pointers are used, but Rust's memory model is still undefined. If
you're | |
299 /// getting a bad/strange runtime error, it might be for this reason. | |
300 unsafe fn end_read(&self, elems_read: usize) -> MojoResult { | |
301 let elem_size = mem::size_of::<T>(); | |
302 MojoResult::from_code(ffi::MojoEndReadData(self.handle.get_native_handle
(), | |
303 (elems_read * elem_size) as u
32)) | |
304 } | |
305 } | |
306 | |
307 impl<T> CastHandle for Consumer<T> { | |
308 /// Generates a Consumer from an untyped handle wrapper | |
309 /// See mojo::system::handle for information on untyped vs. typed | |
310 unsafe fn from_untyped(handle: handle::UntypedHandle) -> Self { | |
311 Consumer::<T> { | |
312 handle: handle, | |
313 _elem_type: marker::PhantomData, | |
314 } | |
315 } | |
316 | |
317 /// Consumes this object and produces a plain handle wrapper | |
318 /// See mojo::system::handle for information on untyped vs. typed | |
319 fn as_untyped(self) -> handle::UntypedHandle { | |
320 self.handle | |
321 } | |
322 } | |
323 | |
324 impl<T> Handle for Consumer<T> { | |
325 /// Returns the native handle wrapped by this structure. | |
326 /// | |
327 /// See mojo::system::handle for information on handle wrappers | |
328 fn get_native_handle(&self) -> MojoHandle { | |
329 self.handle.get_native_handle() | |
330 } | |
331 } | |
332 | |
333 /// Represents the consumer half of a data pipe. | |
334 /// This data structure wraps a handle and acts | |
335 /// effectively as a typed handle. | |
336 /// | |
337 /// The purpose of the _elem_type field is to associate | |
338 /// a type with the consumer, as a data pipe works | |
339 /// in elements. | |
340 pub struct Producer<T> { | |
341 handle: handle::UntypedHandle, | |
342 _elem_type: marker::PhantomData<T>, | |
343 } | |
344 | |
345 impl<T> Producer<T> { | |
346 /// Perform a write operation on the producer end of the data pipe. | |
347 /// Returns the number of elements actually written. | |
348 pub fn write(&self, data: &[T], flags: WriteFlags) -> Result<usize, MojoResu
lt> { | |
349 let mut num_bytes = (data.len() * mem::size_of::<T>()) as u32; | |
350 let r = MojoResult::from_code(unsafe { | |
351 ffi::MojoWriteData(self.handle.get_native_handle(), | |
352 data.as_ptr() as *const ffi::c_void, | |
353 &mut num_bytes as *mut u32, | |
354 flags) | |
355 }); | |
356 if r != MojoResult::Okay { | |
357 Err(r) | |
358 } else { | |
359 Ok(num_bytes as usize) | |
360 } | |
361 } | |
362 | |
363 /// Start two-phase write and return a WriteDataBuffer to perform | |
364 /// write and commit. | |
365 /// | |
366 /// Borrows self as mutable so that no other operation may happen on | |
367 /// the producer until the two-phase write is committed. | |
368 pub fn begin(&self, flags: WriteFlags) -> Result<WriteDataBuffer<T>, MojoRes
ult> { | |
369 let wrapped_result = unsafe { self.begin_write(flags) }; | |
370 match wrapped_result { | |
371 Ok(arr) => { | |
372 Ok(WriteDataBuffer::<T> { | |
373 buffer: arr, | |
374 parent: self, | |
375 }) | |
376 } | |
377 Err(r) => Err(r), | |
378 } | |
379 } | |
380 | |
381 /// A private function that performs the first half of two-phase writing. | |
382 /// Kept private because it is unsafe to use (the array received may not | |
383 /// be valid if end_write is performed). | |
384 unsafe fn begin_write(&self, flags: WriteFlags) -> Result<&mut [T], MojoResu
lt> { | |
385 let mut buf_num_bytes: u32 = 0; | |
386 let mut pbuf: *mut ffi::c_void = mem::uninitialized(); | |
387 let r = MojoResult::from_code(ffi::MojoBeginWriteData(self.handle.get_na
tive_handle(), | |
388 &mut pbuf, | |
389 &mut buf_num_bytes
as *mut u32, | |
390 flags)); | |
391 if r != MojoResult::Okay { | |
392 Err(r) | |
393 } else { | |
394 let buf_elems = (buf_num_bytes as usize) / mem::size_of::<T>(); | |
395 let buf = slice::from_raw_parts_mut(pbuf as *mut T, buf_elems); | |
396 Ok(buf) | |
397 } | |
398 } | |
399 | |
400 /// A private function that performs the second half of two-phase writing. | |
401 /// Kept private because it is unsafe to use (the array received from start_
write | |
402 /// may not be valid if end_write is performed). | |
403 /// | |
404 /// Also assumes loads/stores aren't reordered such that a load/store may be | |
405 /// optimized to be run AFTER MojoEndWriteData(). In general, this is true a
s long | |
406 /// as raw pointers are used, but Rust's memory model is still undefined. If
you're | |
407 /// getting a bad/strange runtime error, it might be for this reason. | |
408 unsafe fn end_write(&self, elems_written: usize) -> MojoResult { | |
409 let elem_size = mem::size_of::<T>(); | |
410 MojoResult::from_code(ffi::MojoEndWriteData(self.handle.get_native_handl
e(), | |
411 (elems_written * elem_size)
as u32)) | |
412 } | |
413 } | |
414 | |
415 impl<T> CastHandle for Producer<T> { | |
416 /// Generates a Consumer from an untyped handle wrapper | |
417 /// See mojo::system::handle for information on untyped vs. typed | |
418 unsafe fn from_untyped(handle: handle::UntypedHandle) -> Self { | |
419 Producer::<T> { | |
420 handle: handle, | |
421 _elem_type: marker::PhantomData, | |
422 } | |
423 } | |
424 | |
425 /// Consumes this object and produces a plain handle wrapper | |
426 /// See mojo::system::handle for information on untyped vs. typed | |
427 fn as_untyped(self) -> handle::UntypedHandle { | |
428 self.handle | |
429 } | |
430 } | |
431 | |
432 impl<T> Handle for Producer<T> { | |
433 /// Returns the native handle wrapped by this structure. | |
434 /// | |
435 /// See mojo::system::handle for information on handle wrappers | |
436 fn get_native_handle(&self) -> MojoHandle { | |
437 self.handle.get_native_handle() | |
438 } | |
439 } | |
OLD | NEW |