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 Zircon fifo objects.
6 
7 use {AsHandleRef, HandleBased, Handle, HandleRef, Status};
8 use {sys, ok};
9 
10 /// An object representing a Zircon 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 impl_handle_based!(Fifo);
16 
17 impl Fifo {
18     /// Create a pair of fifos and return their endpoints. Writing to one endpoint enqueues an
19     /// element into the fifo from which the opposing endpoint reads. Wraps the
20     /// [zx_fifo_create](https://fuchsia.googlesource.com/zircon/+/master/docs/syscalls/fifo_create.md)
21     /// syscall.
create(elem_count: u32, elem_size: u32) -> Result<(Fifo, Fifo), Status>22     pub fn create(elem_count: u32, elem_size: u32)
23         -> Result<(Fifo, Fifo), Status>
24     {
25         let mut out0 = 0;
26         let mut out1 = 0;
27         let options = 0;
28         let status = unsafe {
29             sys::zx_fifo_create(elem_count, elem_size, options, &mut out0, &mut out1)
30         };
31         ok(status)?;
32         unsafe { Ok((
33             Self::from(Handle::from_raw(out0)),
34             Self::from(Handle::from_raw(out1))
35         ))}
36     }
37 
38     /// Attempts to write some number of elements into the fifo. The number of bytes written will be
39     /// rounded down to a multiple of the fifo's element size.
40     /// Return value (on success) is number of elements actually written.
41     ///
42     /// Wraps
43     /// [zx_fifo_write](https://fuchsia.googlesource.com/zircon/+/master/docs/syscalls/fifo_write.md).
write(&self, bytes: &[u8]) -> Result<u32, Status>44     pub fn write(&self, bytes: &[u8]) -> Result<u32, Status> {
45         let mut num_entries_written = 0;
46         let status = unsafe {
47             sys::zx_fifo_write(self.raw_handle(), bytes.as_ptr(), bytes.len(),
48                 &mut num_entries_written)
49         };
50         ok(status).map(|()| num_entries_written)
51     }
52 
53     /// Attempts to read some number of elements out of the fifo. The number of bytes read will
54     /// always be a multiple of the fifo's element size.
55     /// Return value (on success) is number of elements actually read.
56     ///
57     /// Wraps
58     /// [zx_fifo_read](https://fuchsia.googlesource.com/zircon/+/master/docs/syscalls/fifo_read.md).
read(&self, bytes: &mut [u8]) -> Result<u32, Status>59     pub fn read(&self, bytes: &mut [u8]) -> Result<u32, Status> {
60         let mut num_entries_read = 0;
61         let status = unsafe {
62             sys::zx_fifo_read(self.raw_handle(), bytes.as_mut_ptr(), bytes.len(),
63                 &mut num_entries_read)
64         };
65         ok(status).map(|()| num_entries_read)
66     }
67 }
68 
69 #[cfg(test)]
70 mod tests {
71     use super::*;
72 
73     #[test]
fifo_basic()74     fn fifo_basic() {
75         let (fifo1, fifo2) = Fifo::create(4, 2).unwrap();
76 
77         // Trying to write less than one element should fail.
78         assert_eq!(fifo1.write(b""), Err(Status::OUT_OF_RANGE));
79         assert_eq!(fifo1.write(b"h"), Err(Status::OUT_OF_RANGE));
80 
81         // Should write one element "he" and ignore the last half-element as it rounds down.
82         assert_eq!(fifo1.write(b"hex").unwrap(), 1);
83 
84         // Should write three elements "ll" "o " "wo" and drop the rest as it is full.
85         assert_eq!(fifo1.write(b"llo worlds").unwrap(), 3);
86 
87         // Now that the fifo is full any further attempts to write should fail.
88         assert_eq!(fifo1.write(b"blah blah"), Err(Status::SHOULD_WAIT));
89 
90         // Read all 4 entries from the other end.
91         let mut read_vec = vec![0; 8];
92         assert_eq!(fifo2.read(&mut read_vec).unwrap(), 4);
93         assert_eq!(read_vec, b"hello wo");
94 
95         // Reading again should fail as the fifo is empty.
96         assert_eq!(fifo2.read(&mut read_vec), Err(Status::SHOULD_WAIT));
97     }
98 }
99