Skip to main content

regio/
traits.rs

1// Copyright 2026 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//! Register access abstracted as traits.
6//!
7//! Routines involving [`Register`] instances can be written generically against
8//! these traits to aid testability. See [`testing`](crate::testing) for
9//! utilities also implementing these traits that may be supplied instead in
10//! tests.
11
12use super::{
13    IoHandle, LayoutOver, ReadHandle, Readable, Register, SafeWrite, UnsafeWrite, Writable,
14    WriteHandle,
15};
16
17/// A trait representing a readable register.
18pub trait ReadReg<Layout> {
19    fn read(&self) -> Layout;
20}
21
22/// A trait representing a safe-writable register.
23pub trait SafeWriteReg<Layout> {
24    fn write(&self, value: Layout);
25
26    fn modify<ModifyFn, Ret>(&self, cb: ModifyFn) -> Ret
27    where
28        ModifyFn: FnOnce(&mut Layout) -> Ret,
29        Self: ReadReg<Layout>,
30    {
31        let mut value = self.read();
32        let ret = cb(&mut value);
33        self.write(value);
34        ret
35    }
36}
37
38/// A trait representing an unsafe-writable register.
39pub trait UnsafeWriteReg<Layout> {
40    /// # Safety
41    ///
42    /// The caller must guarantee that the write does not result in
43    /// undefined behaviour.
44    unsafe fn write(&self, value: Layout);
45
46    /// # Safety
47    ///
48    /// The caller must guarantee that the write does not result in
49    /// undefined behaviour.
50    unsafe fn modify<ModifyFn, Ret>(&self, cb: ModifyFn) -> Ret
51    where
52        ModifyFn: FnOnce(&mut Layout) -> Ret,
53        Self: ReadReg<Layout>,
54    {
55        let mut value = self.read();
56        let ret = cb(&mut value);
57        // Safety: Justification deferred to the caller.
58        unsafe { self.write(value) };
59        ret
60    }
61}
62
63/// A trait representing a register that is both readable and safe-writable. It
64/// is automatically implemented for any type that implements both
65/// [`ReadReg`] and [`SafeWriteReg`].
66pub trait RwSafeReg<Layout>: ReadReg<Layout> + SafeWriteReg<Layout> {}
67impl<Layout, R> RwSafeReg<Layout> for R where R: ReadReg<Layout> + SafeWriteReg<Layout> {}
68
69/// A trait representing a register that is both readable and unsafe-writable.
70/// It is automatically implemented for any type that implements both
71/// [`ReadReg`] and [`UnsafeWriteReg`].
72pub trait RwUnsafeReg<Layout>: ReadReg<Layout> + UnsafeWriteReg<Layout> {}
73impl<Layout, R> RwUnsafeReg<Layout> for R where R: ReadReg<Layout> + UnsafeWriteReg<Layout> {}
74
75impl<Layout, R: ReadReg<Layout>> ReadReg<Layout> for &R {
76    fn read(&self) -> Layout {
77        (*self).read()
78    }
79}
80
81impl<Layout, R: UnsafeWriteReg<Layout>> UnsafeWriteReg<Layout> for &R {
82    unsafe fn write(&self, value: Layout) {
83        unsafe { (*self).write(value) }
84    }
85}
86
87impl<Layout, R: SafeWriteReg<Layout>> SafeWriteReg<Layout> for &R {
88    fn write(&self, value: Layout) {
89        (*self).write(value)
90    }
91}
92
93//
94// Register of course implements the above traits.
95//
96
97impl<Layout, Access, Io> ReadReg<Layout> for Register<Layout, Access, Io>
98where
99    Layout: LayoutOver<<Io as IoHandle>::Base>,
100    Access: Readable,
101    Io: ReadHandle,
102{
103    fn read(&self) -> Layout {
104        Register::read(self)
105    }
106}
107
108impl<Layout, R, Io> SafeWriteReg<Layout> for Register<Layout, (R, SafeWrite), Io>
109where
110    Layout: LayoutOver<<Io as IoHandle>::Base>,
111    (R, SafeWrite): Writable,
112    Io: WriteHandle,
113{
114    fn write(&self, value: Layout) {
115        Register::<_, (R, SafeWrite), _>::write(self, value);
116    }
117}
118
119impl<Layout, R, Io> UnsafeWriteReg<Layout> for Register<Layout, (R, UnsafeWrite), Io>
120where
121    Layout: LayoutOver<<Io as IoHandle>::Base>,
122    (R, UnsafeWrite): Writable,
123    Io: WriteHandle,
124{
125    unsafe fn write(&self, value: Layout) {
126        unsafe { Register::<_, (R, UnsafeWrite), _>::write(self, value) };
127    }
128}