fetish_lib/
type_id.rs

1use std::collections::HashMap;
2use crate::context::*;
3use crate::params::*;
4use crate::displayable_with_context::*;
5use std::fmt;
6use rand::prelude::*;
7
8///A directory of [`Type`]s associating them to [`TypeId`]s, used as
9///part of the specification of a [`Context`]. There can be multiple
10///`Type::VecType`s with different [`TypeId`]s, but given argument
11///and return [`TypeId`]s, this directory may only contain at most one
12///[`TypeId`] with the corresponding `Type::FuncType`.
13pub struct TypeInfoDirectory {
14    info_vec : Vec::<Type>,
15    func_ind_map : HashMap<(TypeId, TypeId), TypeId>,
16    ret_map : HashMap::<TypeId, Vec::<(TypeId, TypeId)>>
17}
18
19impl TypeInfoDirectory {
20    ///Creates an empty [`TypeInfoDirectory`].
21    pub fn new() -> Self {
22        TypeInfoDirectory {
23            info_vec : Vec::new(),
24            func_ind_map : HashMap::new(),
25            ret_map : HashMap::new()
26        }
27    }
28    ///Adds the given [`Type`] to this [`TypeInfoDirectory`], and
29    ///returns the [`TypeId`] that it was assigned.
30    pub fn add(&mut self, info : Type) -> TypeId {
31        let added_type_id : usize = self.info_vec.len();
32
33        self.ret_map.insert(added_type_id, Vec::new());
34
35        if let Type::FuncType(arg_type, ret_type) = info {
36            let pair = (arg_type, ret_type);
37            if (self.func_ind_map.contains_key(&pair)) {
38                return *self.func_ind_map.get(&pair).unwrap();
39            } else {
40                self.func_ind_map.insert(pair, added_type_id);
41            }
42
43            let ret_row = self.ret_map.get_mut(&ret_type).unwrap();
44            ret_row.push((added_type_id, arg_type));
45        }
46
47        self.info_vec.push(info); 
48        added_type_id
49    }
50    ///Gets the total number of types stored in this [`TypeInfoDirectory`].
51    ///Since [`TypeId`]s are allocated consecutively, it's correct to use
52    ///this as an iteration bound if you want to iterate over all [`TypeId`]s stored here.
53    pub fn get_total_num_types(&self) -> usize {
54        self.info_vec.len()
55    }
56    ///Returns true iff this [`TypeInfoDirectory`] has a registered [`TypeId`] for
57    ///`Type::FuncType(arg_type_id, ret_type_id)`.
58    pub fn has_func_type(&self, arg_type_id : TypeId, ret_type_id : TypeId) -> bool {
59        let pair = (arg_type_id, ret_type_id);
60        self.func_ind_map.contains_key(&pair)
61    }
62    ///Assuming that there is a [`TypeId`] for a function from the given argument [`TypeId`]
63    ///to the given return [`TypeId`], yields the [`TypeId`] of the function type.
64    pub fn get_func_type_id(&self, arg_type_id : TypeId, ret_type_id : TypeId) -> TypeId {
65        let pair = (arg_type_id, ret_type_id);
66        *self.func_ind_map.get(&pair).unwrap()
67    }
68    ///Gets the [`Type`] information stored for the given [`TypeId`].
69    pub fn get_type(&self, id : TypeId) -> Type {
70        self.info_vec[id]
71    }
72    ///Gets all `(func_type_id, arg_type_id)` pairs which may be applied to yield the
73    ///given [`TypeId`].
74    pub fn get_application_type_ids(&self, id : TypeId) -> Vec::<(TypeId, TypeId)> {
75        self.ret_map.get(&id).unwrap().clone()
76    }
77    ///Given the [`TypeId`] of a function type, yields the [`TypeId`] of the return type.
78    pub fn get_ret_type_id(&self, func_type_id : TypeId) -> TypeId {
79        let func_type = self.get_type(func_type_id);
80        if let Type::FuncType(_, ret_type_id) = func_type {
81            ret_type_id
82        } else {
83            panic!();
84        }
85    }
86    ///Returns true iff the given [`TypeId`] points to a `Type::VecType`.
87    pub fn is_vector_type(&self, id : TypeId) -> bool {
88        let kind = self.get_type(id);
89        match (kind) {
90            Type::FuncType(_, _) => false,
91            Type::VecType(_) => true
92        }
93    }
94    ///Given the [`TypeId`] of a function type, yields the [`TypeId`] of the argument type.
95    pub fn get_arg_type_id(&self, func_type_id : TypeId) -> TypeId {
96        let func_type = self.get_type(func_type_id);
97        if let Type::FuncType(arg_type_id, _) = func_type {
98            arg_type_id
99        } else {
100            panic!();
101        }
102    }
103    ///Assuming that the given [`TypeId`] points to a `Type::VecType`, yields the
104    ///declared number of dimensions for that type's base space.
105    pub fn get_dimension(&self, vec_type_id : TypeId) -> usize {
106        let vec_type = self.get_type(vec_type_id);
107        if let Type::VecType(dim) = vec_type {
108            dim
109        } else {
110            panic!();
111        }
112    }
113}
114
115///Type alias for a `usize` index into a [`TypeInfoDirectory`]'s storage of
116///[`Type`]s. These are assumed to uniquely identify a type, whereas there may
117///be multiple [`TypeId`]s for the same [`Type`]. This is done so that
118///different vector types of the same dimension can potentially have different
119///canonical feature mappings, for instance, if one represents 2d images, and
120///the other represents 1d signals.
121pub type TypeId = usize;
122
123///Fundamental information about a type, generally indexed by a [`TypeId`] and
124///stored in a [`TypeInfoDirectory`].
125#[derive(Copy, Eq, PartialEq, Hash, Debug, Clone)]
126pub enum Type {
127    ///A type for vectors with the given declared number of dimensions for their base space
128    VecType(usize),
129    ///A type for functions which map elements of the former [`TypeId`] to the latter [`TypeId`],
130    ///which is consequently only truly meaningful in the context of a [`TypeInfoDirectory`].
131    FuncType(TypeId, TypeId)
132}
133
134impl DisplayableWithContext for Type {
135    fn display(&self, ctxt : &Context) -> String {
136        match (self) {
137            Type::VecType(n) => format!("{}", n),
138            Type::FuncType(arg, ret) => format!("({} -> {})", 
139                                        ctxt.get_type(*arg).display(ctxt), 
140                                        ctxt.get_type(*ret).display(ctxt))
141        }
142    }
143}