blob: 1a5b42c6d6f8cfcffa0d9eb200a6e4d2ee009f28 [file] [log] [blame]
// Copyright 2024 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.
use fuchsia_zircon as zx;
use moniker::Moniker;
use std::{
collections::HashMap,
sync::{Arc, Mutex},
};
use zx::{AsHandleRef, HandleBased, Koid};
use super::context::ModelContext;
const KOID_ERROR: &str = "basic info should not require any rights";
pub struct InstanceToken(zx::Event);
impl Clone for InstanceToken {
fn clone(&self) -> Self {
Self(self.0.duplicate_handle(zx::Rights::SAME_RIGHTS).unwrap())
}
}
impl From<InstanceToken> for zx::Event {
fn from(value: InstanceToken) -> Self {
value.0
}
}
impl From<zx::Event> for InstanceToken {
fn from(value: zx::Event) -> Self {
InstanceToken(value)
}
}
/// [`InstanceRegistry`] maintains mapping from [`InstanceToken`] KOIDs to the
/// moniker of those component instances.
pub struct InstanceRegistry {
koid_to_moniker: Mutex<HashMap<Koid, Moniker>>,
}
impl InstanceRegistry {
pub fn new() -> Arc<Self> {
Arc::new(Self { koid_to_moniker: Mutex::new(HashMap::new()) })
}
fn add(&self, moniker: Moniker) -> InstanceToken {
let event = zx::Event::create();
let koid = event.get_koid().expect(KOID_ERROR);
self.koid_to_moniker.lock().unwrap().insert(koid, moniker);
InstanceToken(event)
}
#[cfg(test)]
pub fn add_for_tests(&self, moniker: Moniker) -> InstanceToken {
self.add(moniker)
}
/// Looks up the moniker of a component given an [`InstanceToken`].
///
/// If this method returns `None`, then either the component instance has
/// been destroyed, or the token was not minted by component_manager.
pub fn get(&self, token: &InstanceToken) -> Option<Moniker> {
let koid = token.0.get_koid().expect(KOID_ERROR);
self.koid_to_moniker.lock().unwrap().get(&koid).cloned()
}
fn remove(&self, koid: Koid) {
self.koid_to_moniker.lock().unwrap().remove(&koid);
}
}
/// [`InstanceTokenState`] caches a minted [`InstanceToken`] and remembers to
/// unregister it from the registry when the state is dropped.
pub enum InstanceTokenState {
Unset,
Set { token: InstanceToken, context: Arc<ModelContext> },
}
impl InstanceTokenState {
/// Gets a token corresponding to the provided component instance.
pub fn set(&mut self, moniker: &Moniker, context: &Arc<ModelContext>) -> InstanceToken {
match self {
InstanceTokenState::Unset => {
let token = context.instance_registry().add(moniker.clone());
*self = InstanceTokenState::Set { token: token.clone(), context: context.clone() };
token
}
InstanceTokenState::Set { token, .. } => token.clone(),
}
}
}
impl Default for InstanceTokenState {
fn default() -> Self {
InstanceTokenState::Unset
}
}
impl Drop for InstanceTokenState {
fn drop(&mut self) {
match self {
InstanceTokenState::Unset => {}
InstanceTokenState::Set { token, context } => {
context.instance_registry().remove(token.0.get_koid().expect(KOID_ERROR));
}
}
}
}