just playing with tangled
at globpattern 99 lines 2.6 kB view raw
1// Copyright 2024 The Jujutsu Authors 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// https://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15#![allow(missing_docs)] 16 17use std::any::Any; 18use std::any::TypeId; 19use std::collections::HashMap; 20 21/// Type-safe map that stores objects of arbitrary types. 22/// 23/// This allows extensions to store and retrieve their own types unknown to 24/// jj_lib safely. 25#[derive(Default)] 26pub struct ExtensionsMap { 27 values: HashMap<TypeId, Box<dyn Any>>, 28} 29 30impl ExtensionsMap { 31 /// Creates an empty ExtensionsMap. 32 pub fn empty() -> Self { 33 Default::default() 34 } 35 36 /// Returns the specified type if it has already been inserted. 37 pub fn get<V: Any>(&self) -> Option<&V> { 38 self.values 39 .get(&TypeId::of::<V>()) 40 .map(|v| v.downcast_ref::<V>().unwrap()) 41 } 42 43 /// Inserts a new instance of the specified type. 44 /// 45 /// Requires that this type has not been inserted before. 46 pub fn insert<V: Any>(&mut self, value: V) { 47 assert!(self 48 .values 49 .insert(TypeId::of::<V>(), Box::new(value)) 50 .is_none()); 51 } 52} 53 54#[cfg(test)] 55mod tests { 56 use super::*; 57 58 struct TestTypeA; 59 impl TestTypeA { 60 fn get_a(&self) -> &'static str { 61 "a" 62 } 63 } 64 65 struct TestTypeB; 66 impl TestTypeB { 67 fn get_b(&self) -> &'static str { 68 "b" 69 } 70 } 71 72 #[test] 73 fn test_empty() { 74 let extensions_map = ExtensionsMap::empty(); 75 assert!(extensions_map.get::<TestTypeA>().is_none()); 76 assert!(extensions_map.get::<TestTypeB>().is_none()); 77 } 78 79 #[test] 80 fn test_retrieval() { 81 let mut extensions_map = ExtensionsMap::empty(); 82 extensions_map.insert(TestTypeA); 83 extensions_map.insert(TestTypeB); 84 assert_eq!( 85 extensions_map 86 .get::<TestTypeA>() 87 .map(|a| a.get_a()) 88 .unwrap_or(""), 89 "a" 90 ); 91 assert_eq!( 92 extensions_map 93 .get::<TestTypeB>() 94 .map(|b| b.get_b()) 95 .unwrap_or(""), 96 "b" 97 ); 98 } 99}