blob: 685fab29377c63bc8b43139d72aaddb2d01ece6f [file] [log] [blame]
// Copyright 2024 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use core::ops::{Deref, DerefMut};
/// An RAII read lock guard which can point to a subfield of the protected data.
pub struct MappedGuard<G: Deref, M: RwMapping<Arg = G::Target>> {
guard: G,
mapping: M,
}
impl<G: Deref, M: RwMapping<Arg = G::Target>> MappedGuard<G, M> {
/// Create a new MappedGuard from a guard and a mapping.
pub fn new(guard: G, mapping: M) -> Self {
Self { guard, mapping }
}
/// Un-map this guard returning the bare guard.
pub fn unmap(self) -> G {
self.guard
}
/// Apply another mapping to the guard. This returns an instance that applies the current
/// mapping and then the given mapping.
pub fn map<R>(
self,
m: impl RwMapping<Arg = M::Ret, Ret = R>,
) -> MappedGuard<G, impl RwMapping<Arg = G::Target, Ret = R>>
where
G::Target: Sized,
M::Ret: 'static,
{
MappedGuard {
guard: self.guard,
mapping: compose(self.mapping, m),
}
}
}
impl<G: Deref, M: RwMapping<Arg = G::Target>> Deref for MappedGuard<G, M> {
type Target = M::Ret;
fn deref(&self) -> &Self::Target {
self.mapping.map(&*self.guard)
}
}
impl<G: DerefMut, M: RwMapping<Arg = G::Target>> DerefMut for MappedGuard<G, M> {
fn deref_mut(&mut self) -> &mut Self::Target {
self.mapping.map_mut(&mut *self.guard)
}
}
/// Mapping functions which define how to map from one locked data type to a component of that locked data
pub trait RwMapping {
/// The original locked data type
type Arg;
/// The returned mapped locked data type which is a component of the original locked data
type Ret;
/// Maps from Arg into Ret
fn map<'a>(&self, arg: &'a Self::Arg) -> &'a Self::Ret;
/// Mutably maps from Arg into Ret
fn map_mut<'a>(&self, arg: &'a mut Self::Arg) -> &'a mut Self::Ret;
}
/// Compose two RwMapping instances into a new RwMapping
fn compose<T, U, R>(
a: impl RwMapping<Arg = T, Ret = U>,
b: impl RwMapping<Arg = U, Ret = R>,
) -> impl RwMapping<Arg = T, Ret = R>
where
U: 'static,
{
struct Composed<A, B>(A, B);
impl<T, U, R, A, B> RwMapping for Composed<A, B>
where
A: RwMapping<Arg = T, Ret = U>,
B: RwMapping<Arg = U, Ret = R>,
U: 'static,
{
type Arg = T;
type Ret = R;
fn map<'a>(&self, arg: &'a Self::Arg) -> &'a Self::Ret {
let u = self.0.map(arg);
let r = self.1.map(u);
r
}
fn map_mut<'a>(&self, arg: &'a mut Self::Arg) -> &'a mut Self::Ret {
let u = self.0.map_mut(arg);
let r = self.1.map_mut(u);
r
}
}
Composed(a, b)
}