starnix_uapi/
user_value.rs

1// Copyright 2024 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
5use std::ops::Range;
6use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
7
8/// A value Starnix has received from userspace.
9///
10/// Typically, these values are received in syscall arguments and need to be validated before they
11/// can be used directly. For example, integers need to be checked for overflow during arithmetical
12/// operation.
13#[derive(Debug, Clone, Copy, Eq, PartialEq, IntoBytes, KnownLayout, FromBytes, Immutable)]
14#[repr(transparent)]
15pub struct UserValue<T>(T);
16
17impl<T: Copy + Eq + IntoBytes + FromBytes + Immutable> UserValue<T> {
18    /// Create a UserValue from a raw value provided by userspace.
19    pub fn from_raw(raw: T) -> Self {
20        Self(raw)
21    }
22
23    /// The raw value that the user provided.
24    pub fn raw(&self) -> T {
25        self.0
26    }
27
28    /// Attempt to convert this value into another type.
29    pub fn try_into<U: TryFrom<T>>(self) -> Result<U, <U as TryFrom<T>>::Error> {
30        U::try_from(self.0)
31    }
32}
33
34impl<T: Copy + PartialOrd> UserValue<T> {
35    /// Returns the value that the user provided if the value is in the given range.
36    pub fn validate(&self, range: Range<T>) -> Option<T> {
37        if range.contains(&self.0) { Some(self.0) } else { None }
38    }
39}
40
41/// Implements TryFrom for UserValue of specific types
42macro_rules! impl_try_from_user_value {
43    {
44        $(
45            $source:ty => $target:ty
46        ),+
47        $(,)?
48    } => {
49        $(
50            impl TryFrom<$source> for UserValue<$target> {
51                type Error = ();
52
53                fn try_from(u: $source) -> Result<Self, Self::Error> {
54                    let t = u.try_into().map_err(|_| ())?;
55                    Ok(Self::from_raw(t))
56                }
57            }
58        )*
59    }
60}
61
62impl_try_from_user_value! {
63    u32 => usize,
64    u64 => usize,
65    usize => u32,
66    usize => u64,
67}
68
69impl<T: Copy + Eq + IntoBytes + FromBytes + Immutable> From<T> for UserValue<T> {
70    fn from(value: T) -> Self {
71        Self::from_raw(value)
72    }
73}
74
75impl<T: PartialEq<T> + Copy + Eq + IntoBytes + FromBytes + Immutable> PartialEq<T>
76    for UserValue<T>
77{
78    fn eq(&self, other: &T) -> bool {
79        self.0 == *other
80    }
81}