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