@@ -18,6 +18,7 @@ use crate::ast::*;
18
18
use crate :: evaluator:: { EvaluationError , RestrictedEvaluator } ;
19
19
use crate :: extensions:: Extensions ;
20
20
use crate :: parser:: err:: ParseErrors ;
21
+ use crate :: parser:: Loc ;
21
22
use crate :: transitive_closure:: TCNode ;
22
23
use crate :: FromNormalizedStr ;
23
24
use itertools:: Itertools ;
@@ -62,13 +63,43 @@ impl std::fmt::Display for EntityType {
62
63
}
63
64
64
65
/// Unique ID for an entity. These represent entities in the AST.
65
- #[ derive( Serialize , Deserialize , PartialEq , Eq , Debug , Clone , Hash , PartialOrd , Ord ) ]
66
- #[ cfg_attr( feature = "arbitrary" , derive( arbitrary:: Arbitrary ) ) ]
66
+ #[ derive( Serialize , Deserialize , Debug , Clone ) ]
67
67
pub struct EntityUID {
68
68
/// Typename of the entity
69
69
ty : EntityType ,
70
70
/// EID of the entity
71
71
eid : Eid ,
72
+ /// Location of the entity in policy source
73
+ #[ serde( skip) ]
74
+ loc : Option < Loc > ,
75
+ }
76
+
77
+ /// `PartialEq` implementation ignores the `loc`.
78
+ impl PartialEq for EntityUID {
79
+ fn eq ( & self , other : & Self ) -> bool {
80
+ self . ty == other. ty && self . eid == other. eid
81
+ }
82
+ }
83
+ impl Eq for EntityUID { }
84
+
85
+ impl std:: hash:: Hash for EntityUID {
86
+ fn hash < H : std:: hash:: Hasher > ( & self , state : & mut H ) {
87
+ // hash the ty and eid, in line with the `PartialEq` impl which compares
88
+ // the ty and eid.
89
+ self . ty . hash ( state) ;
90
+ self . eid . hash ( state) ;
91
+ }
92
+ }
93
+
94
+ impl PartialOrd for EntityUID {
95
+ fn partial_cmp ( & self , other : & Self ) -> Option < std:: cmp:: Ordering > {
96
+ Some ( self . cmp ( other) )
97
+ }
98
+ }
99
+ impl Ord for EntityUID {
100
+ fn cmp ( & self , other : & Self ) -> std:: cmp:: Ordering {
101
+ self . ty . cmp ( & other. ty ) . then ( self . eid . cmp ( & other. eid ) )
102
+ }
72
103
}
73
104
74
105
impl StaticallyTyped for EntityUID {
@@ -87,6 +118,7 @@ impl EntityUID {
87
118
Self {
88
119
ty : Self :: test_entity_type ( ) ,
89
120
eid : Eid ( eid. into ( ) ) ,
121
+ loc : None ,
90
122
}
91
123
}
92
124
// by default, Coverlay does not track coverage for lines after a line
@@ -113,6 +145,7 @@ impl EntityUID {
113
145
Ok ( Self {
114
146
ty : EntityType :: Specified ( Name :: parse_unqualified_name ( typename) ?) ,
115
147
eid : Eid ( eid. into ( ) ) ,
148
+ loc : None ,
116
149
} )
117
150
}
118
151
@@ -122,11 +155,17 @@ impl EntityUID {
122
155
( self . ty , self . eid )
123
156
}
124
157
158
+ /// Get the source location for this `EntityUID`.
159
+ pub fn loc ( & self ) -> Option < & Loc > {
160
+ self . loc . as_ref ( )
161
+ }
162
+
125
163
/// Create a nominally-typed `EntityUID` with the given typename and EID
126
- pub fn from_components ( name : Name , eid : Eid ) -> Self {
164
+ pub fn from_components ( name : Name , eid : Eid , loc : Option < Loc > ) -> Self {
127
165
Self {
128
166
ty : EntityType :: Specified ( name) ,
129
167
eid,
168
+ loc,
130
169
}
131
170
}
132
171
@@ -135,6 +174,7 @@ impl EntityUID {
135
174
Self {
136
175
ty : EntityType :: Unspecified ,
137
176
eid,
177
+ loc : None ,
138
178
}
139
179
}
140
180
@@ -175,6 +215,17 @@ impl FromNormalizedStr for EntityUID {
175
215
}
176
216
}
177
217
218
+ #[ cfg( feature = "arbitrary" ) ]
219
+ impl < ' a > arbitrary:: Arbitrary < ' a > for EntityUID {
220
+ fn arbitrary ( u : & mut arbitrary:: Unstructured < ' a > ) -> arbitrary:: Result < Self > {
221
+ Ok ( Self {
222
+ ty : u. arbitrary ( ) ?,
223
+ eid : u. arbitrary ( ) ?,
224
+ loc : None ,
225
+ } )
226
+ }
227
+ }
228
+
178
229
/// EID type is just a SmolStr for now
179
230
#[ derive( Serialize , Deserialize , PartialEq , Eq , Debug , Clone , Hash , PartialOrd , Ord ) ]
180
231
pub struct Eid ( SmolStr ) ;
@@ -497,12 +548,14 @@ mod test {
497
548
let e2 = EntityUID :: from_components (
498
549
Name :: parse_unqualified_name ( "test_entity_type" ) . expect ( "should be a valid identifier" ) ,
499
550
Eid ( "foo" . into ( ) ) ,
551
+ None ,
500
552
) ;
501
553
let e3 = EntityUID :: unspecified_from_eid ( Eid ( "foo" . into ( ) ) ) ;
502
554
let e4 = EntityUID :: unspecified_from_eid ( Eid ( "bar" . into ( ) ) ) ;
503
555
let e5 = EntityUID :: from_components (
504
556
Name :: parse_unqualified_name ( "Unspecified" ) . expect ( "should be a valid identifier" ) ,
505
557
Eid ( "foo" . into ( ) ) ,
558
+ None ,
506
559
) ;
507
560
508
561
// an EUID is equal to itself
0 commit comments