zx/
counter.rs

1// Copyright 2025 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 cuonter objects.
6
7use crate::{ok, sys, AsHandleRef, Handle, HandleBased, HandleRef, Status};
8
9/// An object representing a Zircon
10/// [counter](https://fuchsia.dev/fuchsia-src/concepts/objects/counter.md).
11///
12/// As essentially a subtype of `Handle`, it can be freely interconverted.
13#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
14#[repr(transparent)]
15pub struct Counter(Handle);
16impl_handle_based!(Counter);
17
18impl Counter {
19    /// Create a counter object.
20    ///
21    /// This object contains an integer which can be read, written, incremented and
22    /// decremented. Readers can wait on [zx::Signals::COUNTER_POSITIVE] and
23    /// [zx::Signals::COUNTER_NON_POSITIVE] to react on the respective value changes.
24    ///
25    /// See:
26    /// [zx_counter_create](https://fuchsia.dev/fuchsia-src/reference/syscalls/counter_create.md)
27    /// syscall.
28    ///
29    /// # Panics
30    ///
31    /// If the kernel reports no memory available or the process' job policy denies counter creation.
32    pub fn create() -> Counter {
33        let options = 0;
34        let mut handle = 0;
35        let status = unsafe { sys::zx_counter_create(options, &mut handle) };
36        ok(status).expect(
37            "counter creation always succeeds except with OOM or when job policy denies it",
38        );
39        unsafe { Counter::from(Handle::from_raw(handle)) }
40    }
41
42    /// Adds `value` to this counter.
43    pub fn add(&self, value: i64) -> Result<(), Status> {
44        let status = unsafe { sys::zx_counter_add(self.raw_handle(), value) };
45        ok(status)
46    }
47
48    /// Reads the value of this counter.
49    pub fn read(&self) -> Result<i64, Status> {
50        let mut value = 0;
51        let status = unsafe { sys::zx_counter_read(self.raw_handle(), &mut value) };
52        ok(status).map(|()| value)
53    }
54
55    /// Sets the value of this counter to `value`.
56    pub fn write(&self, value: i64) -> Result<(), Status> {
57        let status = unsafe { sys::zx_counter_write(self.raw_handle(), value) };
58        ok(status)
59    }
60}
61
62// These tests are intended to verify the Rust bindings rather the counter
63// Zircon object.  The tests for the Zircon object are part of the core-tests
64// suite.
65#[cfg(test)]
66mod tests {
67    use super::*;
68
69    #[test]
70    fn counter_create() {
71        let counter = Counter::create();
72        assert_eq!(counter.read().unwrap(), 0);
73    }
74
75    #[test]
76    fn counter_add() {
77        let counter = Counter::create();
78        assert_eq!(counter.read().unwrap(), 0);
79        assert!(counter.add(i64::max_value()).is_ok());
80        assert_eq!(counter.read().unwrap(), i64::max_value());
81        assert_eq!(counter.add(1), Err(Status::OUT_OF_RANGE));
82    }
83
84    #[test]
85    fn counter_read_write() {
86        let counter = Counter::create();
87        assert_eq!(counter.read().unwrap(), 0);
88        assert!(counter.write(i64::min_value()).is_ok());
89        assert_eq!(counter.read().unwrap(), i64::min_value());
90    }
91}