]> git.proxmox.com Git - rustc.git/blame - src/librustc/dep_graph/dep_node.rs
New upstream version 1.42.0+dfsg0+pve1
[rustc.git] / src / librustc / dep_graph / dep_node.rs
CommitLineData
041b39d2
XL
1//! This module defines the `DepNode` type which the compiler uses to represent
2//! nodes in the dependency graph. A `DepNode` consists of a `DepKind` (which
3//! specifies the kind of thing it represents, like a piece of HIR, MIR, etc)
4//! and a `Fingerprint`, a 128 bit hash value the exact meaning of which
5//! depends on the node's `DepKind`. Together, the kind and the fingerprint
6//! fully identify a dependency node, even across multiple compilation sessions.
7//! In other words, the value of the fingerprint does not depend on anything
8//! that is specific to a given compilation session, like an unpredictable
0731742a 9//! interning key (e.g., NodeId, DefId, Symbol) or the numeric value of a
041b39d2
XL
10//! pointer. The concept behind this could be compared to how git commit hashes
11//! uniquely identify a given commit and has a few advantages:
12//!
13//! * A `DepNode` can simply be serialized to disk and loaded in another session
14//! without the need to do any "rebasing (like we have to do for Spans and
15//! NodeIds) or "retracing" like we had to do for `DefId` in earlier
16//! implementations of the dependency graph.
17//! * A `Fingerprint` is just a bunch of bits, which allows `DepNode` to
18//! implement `Copy`, `Sync`, `Send`, `Freeze`, etc.
19//! * Since we just have a bit pattern, `DepNode` can be mapped from disk into
0731742a 20//! memory without any post-processing (e.g., "abomination-style" pointer
041b39d2
XL
21//! reconstruction).
22//! * Because a `DepNode` is self-contained, we can instantiate `DepNodes` that
23//! refer to things that do not exist anymore. In previous implementations
24//! `DepNode` contained a `DefId`. A `DepNode` referring to something that
25//! had been removed between the previous and the current compilation session
26//! could not be instantiated because the current compilation session
27//! contained no `DefId` for thing that had been removed.
28//!
29//! `DepNode` definition happens in the `define_dep_nodes!()` macro. This macro
30//! defines the `DepKind` enum and a corresponding `DepConstructor` enum. The
31//! `DepConstructor` enum links a `DepKind` to the parameters that are needed at
32//! runtime in order to construct a valid `DepNode` fingerprint.
33//!
34//! Because the macro sees what parameters a given `DepKind` requires, it can
35//! "infer" some properties for each kind of `DepNode`:
36//!
37//! * Whether a `DepNode` of a given kind has any parameters at all. Some
38//! `DepNode`s, like `Krate`, represent global concepts with only one value.
39//! * Whether it is possible, in principle, to reconstruct a query key from a
40//! given `DepNode`. Many `DepKind`s only require a single `DefId` parameter,
41//! in which case it is possible to map the node's fingerprint back to the
42//! `DefId` it was computed from. In other cases, too much information gets
43//! lost during fingerprint computation.
44//!
45//! The `DepConstructor` enum, together with `DepNode::new()` ensures that only
46//! valid `DepNode` instances can be constructed. For example, the API does not
47//! allow for constructing parameterless `DepNode`s with anything other
48//! than a zeroed out fingerprint. More generally speaking, it relieves the
49//! user of the `DepNode` API of having to know how to compute the expected
50//! fingerprint for a given set of node parameters.
51
9fa01778 52use crate::hir::map::DefPathHash;
9fa01778 53use crate::ich::{Fingerprint, StableHashingContext};
46de9a89
FG
54use crate::mir;
55use crate::mir::interpret::{GlobalId, LitToConstInput};
9fa01778
XL
56use crate::traits;
57use crate::traits::query::{
46de9a89
FG
58 CanonicalPredicateGoal, CanonicalProjectionGoal, CanonicalTyGoal,
59 CanonicalTypeOpAscribeUserTypeGoal, CanonicalTypeOpEqGoal, CanonicalTypeOpNormalizeGoal,
60 CanonicalTypeOpProvePredicateGoal, CanonicalTypeOpSubtypeGoal,
8faf50e0 61};
532ac7d7 62use crate::ty::subst::SubstsRef;
46de9a89
FG
63use crate::ty::{self, ParamEnvAnd, Ty, TyCtxt};
64
65use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
66use rustc_hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX};
67use rustc_hir::HirId;
68use rustc_span::symbol::Symbol;
69use std::fmt;
70use std::hash::Hash;
041b39d2
XL
71
72// erase!() just makes tokens go away. It's used to specify which macro argument
0731742a 73// is repeated (i.e., which sub-expression of the macro we are in) but don't need
041b39d2
XL
74// to actually use any of the arguments.
75macro_rules! erase {
46de9a89 76 ($x:tt) => {{}};
041b39d2
XL
77}
78
0531ce1d
XL
79macro_rules! replace {
80 ($x:tt with $($y:tt)*) => ($($y)*)
81}
82
ea8adc8c 83macro_rules! is_anon_attr {
46de9a89
FG
84 (anon) => {
85 true
86 };
87 ($attr:ident) => {
88 false
89 };
ea8adc8c
XL
90}
91
abe05a73 92macro_rules! is_eval_always_attr {
46de9a89
FG
93 (eval_always) => {
94 true
95 };
96 ($attr:ident) => {
97 false
98 };
abe05a73
XL
99}
100
ea8adc8c
XL
101macro_rules! contains_anon_attr {
102 ($($attr:ident),*) => ({$(is_anon_attr!($attr) | )* false});
103}
104
abe05a73
XL
105macro_rules! contains_eval_always_attr {
106 ($($attr:ident),*) => ({$(is_eval_always_attr!($attr) | )* false});
107}
108
041b39d2
XL
109macro_rules! define_dep_nodes {
110 (<$tcx:tt>
111 $(
ea8adc8c 112 [$($attr:ident),* ]
9fa01778 113 $variant:ident $(( $tuple_arg_ty:ty $(,)? ))*
041b39d2
XL
114 $({ $($struct_arg_name:ident : $struct_arg_ty:ty),* })*
115 ,)*
116 ) => (
117 #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash,
118 RustcEncodable, RustcDecodable)]
119 pub enum DepKind {
120 $($variant),*
121 }
122
123 impl DepKind {
124 #[allow(unreachable_code)]
041b39d2
XL
125 pub fn can_reconstruct_query_key<$tcx>(&self) -> bool {
126 match *self {
127 $(
128 DepKind :: $variant => {
ea8adc8c
XL
129 if contains_anon_attr!($($attr),*) {
130 return false;
131 }
3b2f2976 132
041b39d2
XL
133 // tuple args
134 $({
0531ce1d 135 return <$tuple_arg_ty as DepNodeParams>
041b39d2
XL
136 ::CAN_RECONSTRUCT_QUERY_KEY;
137 })*
138
139 // struct args
140 $({
3b2f2976 141
041b39d2
XL
142 return <( $($struct_arg_ty,)* ) as DepNodeParams>
143 ::CAN_RECONSTRUCT_QUERY_KEY;
144 })*
145
146 true
147 }
148 )*
149 }
150 }
151
ea8adc8c 152 pub fn is_anon(&self) -> bool {
041b39d2
XL
153 match *self {
154 $(
ea8adc8c
XL
155 DepKind :: $variant => { contains_anon_attr!($($attr),*) }
156 )*
157 }
158 }
159
abe05a73
XL
160 pub fn is_eval_always(&self) -> bool {
161 match *self {
162 $(
163 DepKind :: $variant => { contains_eval_always_attr!($($attr), *) }
164 )*
165 }
166 }
167
041b39d2 168 #[allow(unreachable_code)]
041b39d2
XL
169 pub fn has_params(&self) -> bool {
170 match *self {
171 $(
172 DepKind :: $variant => {
173 // tuple args
174 $({
0531ce1d 175 erase!($tuple_arg_ty);
041b39d2
XL
176 return true;
177 })*
178
179 // struct args
180 $({
181 $(erase!($struct_arg_name);)*
182 return true;
183 })*
184
185 false
186 }
187 )*
188 }
189 }
190 }
191
192 pub enum DepConstructor<$tcx> {
193 $(
0531ce1d 194 $variant $(( $tuple_arg_ty ))*
041b39d2
XL
195 $({ $($struct_arg_name : $struct_arg_ty),* })*
196 ),*
197 }
198
199 #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash,
200 RustcEncodable, RustcDecodable)]
201 pub struct DepNode {
202 pub kind: DepKind,
203 pub hash: Fingerprint,
3157f602 204 }
041b39d2
XL
205
206 impl DepNode {
207 #[allow(unreachable_code, non_snake_case)]
dc9dc135
XL
208 pub fn new<'tcx>(tcx: TyCtxt<'tcx>,
209 dep: DepConstructor<'tcx>)
041b39d2 210 -> DepNode
041b39d2
XL
211 {
212 match dep {
213 $(
0531ce1d 214 DepConstructor :: $variant $(( replace!(($tuple_arg_ty) with arg) ))*
041b39d2
XL
215 $({ $($struct_arg_name),* })*
216 =>
217 {
218 // tuple args
219 $({
0531ce1d
XL
220 erase!($tuple_arg_ty);
221 let hash = DepNodeParams::to_fingerprint(&arg, tcx);
041b39d2
XL
222 let dep_node = DepNode {
223 kind: DepKind::$variant,
224 hash
225 };
226
e74abb32 227 #[cfg(debug_assertions)]
041b39d2 228 {
e74abb32
XL
229 if !dep_node.kind.can_reconstruct_query_key() &&
230 (tcx.sess.opts.debugging_opts.incremental_info ||
231 tcx.sess.opts.debugging_opts.query_dep_graph)
232 {
233 tcx.dep_graph.register_dep_node_debug_str(dep_node, || {
234 arg.to_debug_str(tcx)
235 });
236 }
041b39d2
XL
237 }
238
239 return dep_node;
240 })*
241
242 // struct args
243 $({
244 let tupled_args = ( $($struct_arg_name,)* );
245 let hash = DepNodeParams::to_fingerprint(&tupled_args,
246 tcx);
247 let dep_node = DepNode {
248 kind: DepKind::$variant,
249 hash
250 };
251
e74abb32 252 #[cfg(debug_assertions)]
041b39d2 253 {
e74abb32
XL
254 if !dep_node.kind.can_reconstruct_query_key() &&
255 (tcx.sess.opts.debugging_opts.incremental_info ||
256 tcx.sess.opts.debugging_opts.query_dep_graph)
257 {
258 tcx.dep_graph.register_dep_node_debug_str(dep_node, || {
259 tupled_args.to_debug_str(tcx)
260 });
261 }
041b39d2
XL
262 }
263
264 return dep_node;
265 })*
266
267 DepNode {
268 kind: DepKind::$variant,
ff7c6d11 269 hash: Fingerprint::ZERO,
041b39d2
XL
270 }
271 }
272 )*
273 }
274 }
275
276 /// Construct a DepNode from the given DepKind and DefPathHash. This
277 /// method will assert that the given DepKind actually requires a
278 /// single DefId/DefPathHash parameter.
041b39d2
XL
279 pub fn from_def_path_hash(kind: DepKind,
280 def_path_hash: DefPathHash)
281 -> DepNode {
0731742a 282 debug_assert!(kind.can_reconstruct_query_key() && kind.has_params());
041b39d2
XL
283 DepNode {
284 kind,
285 hash: def_path_hash.0,
286 }
287 }
288
9fa01778 289 /// Creates a new, parameterless DepNode. This method will assert
041b39d2
XL
290 /// that the DepNode corresponding to the given DepKind actually
291 /// does not require any parameters.
041b39d2 292 pub fn new_no_params(kind: DepKind) -> DepNode {
0731742a 293 debug_assert!(!kind.has_params());
041b39d2
XL
294 DepNode {
295 kind,
ff7c6d11 296 hash: Fingerprint::ZERO,
041b39d2
XL
297 }
298 }
299
9fa01778 300 /// Extracts the DefId corresponding to this DepNode. This will work
041b39d2
XL
301 /// if two conditions are met:
302 ///
303 /// 1. The Fingerprint of the DepNode actually is a DefPathHash, and
304 /// 2. the item that the DefPath refers to exists in the current tcx.
305 ///
306 /// Condition (1) is determined by the DepKind variant of the
307 /// DepNode. Condition (2) might not be fulfilled if a DepNode
308 /// refers to something from the previous compilation session that
309 /// has been removed.
dc9dc135 310 pub fn extract_def_id(&self, tcx: TyCtxt<'_>) -> Option<DefId> {
041b39d2
XL
311 if self.kind.can_reconstruct_query_key() {
312 let def_path_hash = DefPathHash(self.hash);
8faf50e0
XL
313 tcx.def_path_hash_to_def_id.as_ref()?
314 .get(&def_path_hash).cloned()
041b39d2
XL
315 } else {
316 None
317 }
318 }
319
320 /// Used in testing
321 pub fn from_label_string(label: &str,
322 def_path_hash: DefPathHash)
323 -> Result<DepNode, ()> {
324 let kind = match label {
325 $(
326 stringify!($variant) => DepKind::$variant,
327 )*
328 _ => return Err(()),
329 };
330
331 if !kind.can_reconstruct_query_key() {
332 return Err(());
333 }
334
335 if kind.has_params() {
336 Ok(def_path_hash.to_dep_node(kind))
337 } else {
338 Ok(DepNode::new_no_params(kind))
339 }
340 }
ea8adc8c
XL
341
342 /// Used in testing
343 pub fn has_label_string(label: &str) -> bool {
344 match label {
345 $(
346 stringify!($variant) => true,
347 )*
348 _ => false,
349 }
350 }
351 }
352
353 /// Contains variant => str representations for constructing
354 /// DepNode groups for tests.
355 #[allow(dead_code, non_upper_case_globals)]
356 pub mod label_strs {
357 $(
0731742a 358 pub const $variant: &str = stringify!($variant);
ea8adc8c 359 )*
041b39d2
XL
360 }
361 );
362}
363
364impl fmt::Debug for DepNode {
0bf4aa26 365 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
041b39d2
XL
366 write!(f, "{:?}", self.kind)?;
367
ea8adc8c 368 if !self.kind.has_params() && !self.kind.is_anon() {
041b39d2
XL
369 return Ok(());
370 }
371
372 write!(f, "(")?;
373
9fa01778 374 crate::ty::tls::with_opt(|opt_tcx| {
041b39d2
XL
375 if let Some(tcx) = opt_tcx {
376 if let Some(def_id) = self.extract_def_id(tcx) {
ea8adc8c 377 write!(f, "{}", tcx.def_path_debug_str(def_id))?;
041b39d2
XL
378 } else if let Some(ref s) = tcx.dep_graph.dep_node_debug_str(*self) {
379 write!(f, "{}", s)?;
380 } else {
ea8adc8c 381 write!(f, "{}", self.hash)?;
041b39d2
XL
382 }
383 } else {
ea8adc8c 384 write!(f, "{}", self.hash)?;
041b39d2
XL
385 }
386 Ok(())
387 })?;
388
389 write!(f, ")")
390 }
391}
392
041b39d2 393impl DefPathHash {
041b39d2
XL
394 pub fn to_dep_node(self, kind: DepKind) -> DepNode {
395 DepNode::from_def_path_hash(kind, self)
396 }
397}
398
532ac7d7 399rustc_dep_node_append!([define_dep_nodes!][ <'tcx>
0531ce1d
XL
400 // We use this for most things when incr. comp. is turned off.
401 [] Null,
402
041b39d2
XL
403 // Represents the `Krate` as a whole (the `hir::Krate` value) (as
404 // distinct from the krate module). This is basically a hash of
405 // the entire krate, so if you read from `Krate` (e.g., by calling
0731742a 406 // `tcx.hir().krate()`), we will have to assume that any change
041b39d2
XL
407 // means that you need to be recompiled. This is because the
408 // `Krate` value gives you access to all other items. To avoid
0731742a 409 // this fate, do not call `tcx.hir().krate()`; instead, prefer
041b39d2
XL
410 // wrappers like `tcx.visit_all_items_in_krate()`. If there is no
411 // suitable wrapper, you can use `tcx.dep_graph.ignore()` to gain
412 // access to the krate, but you must remember to add suitable
413 // edges yourself for the individual items that you read.
532ac7d7 414 [eval_always] Krate,
041b39d2
XL
415
416 // Represents the body of a function or method. The def-id is that of the
417 // function/method.
532ac7d7 418 [eval_always] HirBody(DefId),
041b39d2 419
ea8adc8c 420 // Represents the HIR node with the given node-id
532ac7d7 421 [eval_always] Hir(DefId),
ea8adc8c
XL
422
423 // Represents metadata from an extern crate.
532ac7d7
XL
424 [eval_always] CrateMetadata(CrateNum),
425
426 [eval_always] AllLocalTraitImpls,
abe05a73 427
3b2f2976 428 [anon] TraitSelect,
041b39d2 429
e74abb32 430 [] CompileCodegenUnit(Symbol),
532ac7d7
XL
431
432 [eval_always] Analysis(CrateNum),
433]);
434
435pub trait RecoverKey<'tcx>: Sized {
dc9dc135 436 fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self>;
532ac7d7
XL
437}
438
439impl RecoverKey<'tcx> for CrateNum {
dc9dc135 440 fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> {
532ac7d7
XL
441 dep_node.extract_def_id(tcx).map(|id| id.krate)
442 }
443}
444
445impl RecoverKey<'tcx> for DefId {
dc9dc135 446 fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> {
532ac7d7
XL
447 dep_node.extract_def_id(tcx)
448 }
449}
450
451impl RecoverKey<'tcx> for DefIndex {
dc9dc135 452 fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> {
532ac7d7
XL
453 dep_node.extract_def_id(tcx).map(|id| id.index)
454 }
455}
041b39d2 456
dc9dc135 457trait DepNodeParams<'tcx>: fmt::Debug {
041b39d2
XL
458 const CAN_RECONSTRUCT_QUERY_KEY: bool;
459
460 /// This method turns the parameters of a DepNodeConstructor into an opaque
461 /// Fingerprint to be used in DepNode.
462 /// Not all DepNodeParams support being turned into a Fingerprint (they
463 /// don't need to if the corresponding DepNode is anonymous).
dc9dc135 464 fn to_fingerprint(&self, _: TyCtxt<'tcx>) -> Fingerprint {
041b39d2
XL
465 panic!("Not implemented. Accidentally called on anonymous node?")
466 }
467
dc9dc135 468 fn to_debug_str(&self, _: TyCtxt<'tcx>) -> String {
041b39d2
XL
469 format!("{:?}", self)
470 }
54a0048b
SL
471}
472
dc9dc135
XL
473impl<'tcx, T> DepNodeParams<'tcx> for T
474where
475 T: HashStable<StableHashingContext<'tcx>> + fmt::Debug,
041b39d2
XL
476{
477 default const CAN_RECONSTRUCT_QUERY_KEY: bool = false;
54a0048b 478
dc9dc135 479 default fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint {
ea8adc8c 480 let mut hcx = tcx.create_stable_hashing_context();
041b39d2
XL
481 let mut hasher = StableHasher::new();
482
483 self.hash_stable(&mut hcx, &mut hasher);
484
485 hasher.finish()
486 }
487
dc9dc135 488 default fn to_debug_str(&self, _: TyCtxt<'tcx>) -> String {
041b39d2
XL
489 format!("{:?}", *self)
490 }
491}
492
dc9dc135 493impl<'tcx> DepNodeParams<'tcx> for DefId {
041b39d2
XL
494 const CAN_RECONSTRUCT_QUERY_KEY: bool = true;
495
dc9dc135 496 fn to_fingerprint(&self, tcx: TyCtxt<'_>) -> Fingerprint {
0531ce1d 497 tcx.def_path_hash(*self).0
041b39d2
XL
498 }
499
dc9dc135 500 fn to_debug_str(&self, tcx: TyCtxt<'tcx>) -> String {
532ac7d7 501 tcx.def_path_str(*self)
041b39d2
XL
502 }
503}
9e0c209e 504
dc9dc135 505impl<'tcx> DepNodeParams<'tcx> for DefIndex {
ea8adc8c
XL
506 const CAN_RECONSTRUCT_QUERY_KEY: bool = true;
507
dc9dc135 508 fn to_fingerprint(&self, tcx: TyCtxt<'_>) -> Fingerprint {
0731742a 509 tcx.hir().definitions().def_path_hash(*self).0
ea8adc8c
XL
510 }
511
dc9dc135 512 fn to_debug_str(&self, tcx: TyCtxt<'tcx>) -> String {
532ac7d7 513 tcx.def_path_str(DefId::local(*self))
ea8adc8c
XL
514 }
515}
516
dc9dc135 517impl<'tcx> DepNodeParams<'tcx> for CrateNum {
ea8adc8c
XL
518 const CAN_RECONSTRUCT_QUERY_KEY: bool = true;
519
dc9dc135 520 fn to_fingerprint(&self, tcx: TyCtxt<'_>) -> Fingerprint {
46de9a89 521 let def_id = DefId { krate: *self, index: CRATE_DEF_INDEX };
ea8adc8c
XL
522 tcx.def_path_hash(def_id).0
523 }
524
dc9dc135 525 fn to_debug_str(&self, tcx: TyCtxt<'tcx>) -> String {
d9bb1a4e 526 tcx.crate_name(*self).to_string()
ea8adc8c
XL
527 }
528}
529
dc9dc135 530impl<'tcx> DepNodeParams<'tcx> for (DefId, DefId) {
041b39d2
XL
531 const CAN_RECONSTRUCT_QUERY_KEY: bool = false;
532
533 // We actually would not need to specialize the implementation of this
534 // method but it's faster to combine the hashes than to instantiate a full
535 // hashing context and stable-hashing state.
dc9dc135 536 fn to_fingerprint(&self, tcx: TyCtxt<'_>) -> Fingerprint {
041b39d2
XL
537 let (def_id_0, def_id_1) = *self;
538
539 let def_path_hash_0 = tcx.def_path_hash(def_id_0);
540 let def_path_hash_1 = tcx.def_path_hash(def_id_1);
541
542 def_path_hash_0.0.combine(def_path_hash_1.0)
543 }
544
dc9dc135 545 fn to_debug_str(&self, tcx: TyCtxt<'tcx>) -> String {
041b39d2
XL
546 let (def_id_0, def_id_1) = *self;
547
46de9a89 548 format!("({}, {})", tcx.def_path_debug_str(def_id_0), tcx.def_path_debug_str(def_id_1))
041b39d2
XL
549 }
550}
551
dc9dc135 552impl<'tcx> DepNodeParams<'tcx> for HirId {
041b39d2
XL
553 const CAN_RECONSTRUCT_QUERY_KEY: bool = false;
554
555 // We actually would not need to specialize the implementation of this
556 // method but it's faster to combine the hashes than to instantiate a full
557 // hashing context and stable-hashing state.
dc9dc135 558 fn to_fingerprint(&self, tcx: TyCtxt<'_>) -> Fingerprint {
46de9a89 559 let HirId { owner, local_id } = *self;
041b39d2 560
ea8adc8c 561 let def_path_hash = tcx.def_path_hash(DefId::local(owner));
a1dfa0c6 562 let local_id = Fingerprint::from_smaller_hash(local_id.as_u32().into());
041b39d2 563
ea8adc8c 564 def_path_hash.0.combine(local_id)
54a0048b
SL
565 }
566}
5bcae85e
SL
567
568/// A "work product" corresponds to a `.o` (or other) file that we
9fa01778 569/// save in between runs. These IDs do not have a `DefId` but rather
5bcae85e
SL
570/// some independent path or string that persists between runs without
571/// the need to be mapped or unmapped. (This ensures we can serialize
572/// them even in the absence of a tcx.)
46de9a89
FG
573#[derive(
574 Clone,
575 Copy,
576 Debug,
577 PartialEq,
578 Eq,
579 PartialOrd,
580 Ord,
581 Hash,
582 RustcEncodable,
583 RustcDecodable,
584 HashStable
585)]
041b39d2 586pub struct WorkProductId {
46de9a89 587 hash: Fingerprint,
041b39d2
XL
588}
589
590impl WorkProductId {
591 pub fn from_cgu_name(cgu_name: &str) -> WorkProductId {
592 let mut hasher = StableHasher::new();
593 cgu_name.len().hash(&mut hasher);
594 cgu_name.hash(&mut hasher);
46de9a89 595 WorkProductId { hash: hasher.finish() }
041b39d2
XL
596 }
597
598 pub fn from_fingerprint(fingerprint: Fingerprint) -> WorkProductId {
46de9a89 599 WorkProductId { hash: fingerprint }
041b39d2 600 }
7cac9316 601}