]>
Commit | Line | Data |
---|---|---|
ea8adc8c XL |
1 | // Copyright 2017 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 | //! Type-safe bindings for Magenta fifo objects. | |
6 | ||
7 | use {HandleBase, Handle, HandleRef, Status}; | |
8 | use {sys, into_result}; | |
9 | ||
10 | /// An object representing a Magenta fifo. | |
11 | /// | |
12 | /// As essentially a subtype of `Handle`, it can be freely interconverted. | |
13 | #[derive(Debug, Eq, PartialEq)] | |
14 | pub struct Fifo(Handle); | |
15 | ||
16 | impl HandleBase for Fifo { | |
17 | fn get_ref(&self) -> HandleRef { | |
18 | self.0.get_ref() | |
19 | } | |
20 | ||
21 | fn from_handle(handle: Handle) -> Self { | |
22 | Fifo(handle) | |
23 | } | |
24 | } | |
25 | ||
26 | impl Fifo { | |
27 | /// Create a pair of fifos and return their endpoints. Writing to one endpoint enqueues an | |
28 | /// element into the fifo from which the opposing endpoint reads. Wraps the | |
29 | /// [mx_fifo_create](https://fuchsia.googlesource.com/magenta/+/master/docs/syscalls/fifo_create.md) | |
30 | /// syscall. | |
31 | pub fn create(elem_count: u32, elem_size: u32, options: FifoOpts) | |
32 | -> Result<(Fifo, Fifo), Status> | |
33 | { | |
34 | let mut out0 = 0; | |
35 | let mut out1 = 0; | |
36 | let status = unsafe { | |
37 | sys::mx_fifo_create(elem_count, elem_size, options as u32, &mut out0, &mut out1) | |
38 | }; | |
39 | into_result(status, || (Self::from_handle(Handle(out0)), Self::from_handle(Handle(out1)))) | |
40 | } | |
41 | ||
42 | /// Attempts to write some number of elements into the fifo. The number of bytes written will be | |
43 | /// rounded down to a multiple of the fifo's element size. | |
44 | /// Return value (on success) is number of elements actually written. | |
45 | /// | |
46 | /// Wraps | |
47 | /// [mx_fifo_write](https://fuchsia.googlesource.com/magenta/+/master/docs/syscalls/fifo_write.md). | |
48 | pub fn write(&self, bytes: &[u8]) -> Result<u32, Status> { | |
49 | let mut num_entries_written = 0; | |
50 | let status = unsafe { | |
51 | sys::mx_fifo_write(self.raw_handle(), bytes.as_ptr(), bytes.len(), | |
52 | &mut num_entries_written) | |
53 | }; | |
54 | into_result(status, || num_entries_written) | |
55 | } | |
56 | ||
57 | /// Attempts to read some number of elements out of the fifo. The number of bytes read will | |
58 | /// always be a multiple of the fifo's element size. | |
59 | /// Return value (on success) is number of elements actually read. | |
60 | /// | |
61 | /// Wraps | |
62 | /// [mx_fifo_read](https://fuchsia.googlesource.com/magenta/+/master/docs/syscalls/fifo_read.md). | |
63 | pub fn read(&self, bytes: &mut [u8]) -> Result<u32, Status> { | |
64 | let mut num_entries_read = 0; | |
65 | let status = unsafe { | |
66 | sys::mx_fifo_read(self.raw_handle(), bytes.as_mut_ptr(), bytes.len(), | |
67 | &mut num_entries_read) | |
68 | }; | |
69 | into_result(status, || num_entries_read) | |
70 | } | |
71 | } | |
72 | ||
73 | /// Options for creating a fifo pair. | |
74 | #[repr(u32)] | |
75 | #[derive(Debug, Copy, Clone, Eq, PartialEq)] | |
76 | pub enum FifoOpts { | |
77 | /// Default options. | |
78 | Default = 0, | |
79 | } | |
80 | ||
81 | impl Default for FifoOpts { | |
82 | fn default() -> Self { | |
83 | FifoOpts::Default | |
84 | } | |
85 | } | |
86 | ||
87 | #[cfg(test)] | |
88 | mod tests { | |
89 | use super::*; | |
90 | ||
91 | #[test] | |
92 | fn fifo_basic() { | |
93 | let (fifo1, fifo2) = Fifo::create(4, 2, FifoOpts::Default).unwrap(); | |
94 | ||
95 | // Trying to write less than one element should fail. | |
96 | assert_eq!(fifo1.write(b""), Err(Status::ErrOutOfRange)); | |
97 | assert_eq!(fifo1.write(b"h"), Err(Status::ErrOutOfRange)); | |
98 | ||
99 | // Should write one element "he" and ignore the last half-element as it rounds down. | |
100 | assert_eq!(fifo1.write(b"hex").unwrap(), 1); | |
101 | ||
102 | // Should write three elements "ll" "o " "wo" and drop the rest as it is full. | |
103 | assert_eq!(fifo1.write(b"llo worlds").unwrap(), 3); | |
104 | ||
105 | // Now that the fifo is full any further attempts to write should fail. | |
106 | assert_eq!(fifo1.write(b"blah blah"), Err(Status::ErrShouldWait)); | |
107 | ||
108 | // Read all 4 entries from the other end. | |
109 | let mut read_vec = vec![0; 8]; | |
110 | assert_eq!(fifo2.read(&mut read_vec).unwrap(), 4); | |
111 | assert_eq!(read_vec, b"hello wo"); | |
112 | ||
113 | // Reading again should fail as the fifo is empty. | |
114 | assert_eq!(fifo2.read(&mut read_vec), Err(Status::ErrShouldWait)); | |
115 | } | |
116 | } |