| // 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)); |
| } |
| } |
| } |
| } |