blob: 527899f9c9a251951d0e4f52674bb81c0103c229 [file] [log] [blame]
// Copyright 2025 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//! Type-safe bindings for Zircon cuonter objects.
use crate::{ok, sys, AsHandleRef, Handle, HandleBased, HandleRef, Status};
/// An object representing a Zircon
/// [counter](https://fuchsia.dev/fuchsia-src/concepts/objects/counter.md).
///
/// As essentially a subtype of `Handle`, it can be freely interconverted.
#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
#[repr(transparent)]
pub struct Counter(Handle);
impl_handle_based!(Counter);
impl Counter {
/// Create a counter object.
///
/// This object contains an integer which can be read, written, incremented and
/// decremented. Readers can wait on [zx::Signals::COUNTER_POSITIVE] and
/// [zx::Signals::COUNTER_NON_POSITIVE] to react on the respective value changes.
///
/// See:
/// [zx_counter_create](https://fuchsia.dev/fuchsia-src/reference/syscalls/counter_create.md)
/// syscall.
///
/// # Panics
///
/// If the kernel reports no memory available or the process' job policy denies counter creation.
pub fn create() -> Counter {
let options = 0;
let mut handle = 0;
let status = unsafe { sys::zx_counter_create(options, &mut handle) };
ok(status).expect(
"counter creation always succeeds except with OOM or when job policy denies it",
);
unsafe { Counter::from(Handle::from_raw(handle)) }
}
/// Adds `value` to this counter.
pub fn add(&self, value: i64) -> Result<(), Status> {
let status = unsafe { sys::zx_counter_add(self.raw_handle(), value) };
ok(status)
}
/// Reads the value of this counter.
pub fn read(&self) -> Result<i64, Status> {
let mut value = 0;
let status = unsafe { sys::zx_counter_read(self.raw_handle(), &mut value) };
ok(status).map(|()| value)
}
/// Sets the value of this counter to `value`.
pub fn write(&self, value: i64) -> Result<(), Status> {
let status = unsafe { sys::zx_counter_write(self.raw_handle(), value) };
ok(status)
}
}
// These tests are intended to verify the Rust bindings rather the counter
// Zircon object. The tests for the Zircon object are part of the core-tests
// suite.
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn counter_create() {
let counter = Counter::create();
assert_eq!(counter.read().unwrap(), 0);
}
#[test]
fn counter_add() {
let counter = Counter::create();
assert_eq!(counter.read().unwrap(), 0);
assert!(counter.add(i64::max_value()).is_ok());
assert_eq!(counter.read().unwrap(), i64::max_value());
assert_eq!(counter.add(1), Err(Status::OUT_OF_RANGE));
}
#[test]
fn counter_read_write() {
let counter = Counter::create();
assert_eq!(counter.read().unwrap(), 0);
assert!(counter.write(i64::min_value()).is_ok());
assert_eq!(counter.read().unwrap(), i64::min_value());
}
}