Reference Traits
Relevant source files
This document explains the reference trait system that forms the foundation of the weak-map library. The reference traits provide a flexible abstraction layer for working with different types of references (both strong and weak) in a generic way, enabling the core functionality of WeakMap. For details about the map implementations themselves, see WeakMap and StrongMap.
Overview of Reference Traits
The weak-map library defines two fundamental traits that abstract over reference types:
StrongRef- Represents a strong reference that keeps a value aliveWeakRef- Represents a weak reference that doesn't prevent a value from being dropped
These traits allow the WeakMap to work with different types of reference-counted values without being tied to specific implementations.
Sources: src/traits.rs(L3 - L40)
The StrongRef Trait
The StrongRef trait defines an interface for types that represent strong references to heap-allocated values. A strong reference keeps the referenced value alive for as long as the reference exists.
#![allow(unused)] fn main() { pub trait StrongRef { type Weak: WeakRef<Strong = Self>; fn downgrade(&self) -> Self::Weak; fn ptr_eq(&self, other: &Self) -> bool; } }
The trait requires:
| Member | Type | Purpose |
|---|---|---|
| Weak | Associated type | Specifies the corresponding weak reference type |
| downgrade() | Method | Converts a strong reference to a weak reference |
| ptr_eq() | Method | Compares two strong references for pointer equality |
The Weak associated type establishes a relationship with the WeakRef trait, ensuring that both traits are implemented in a compatible way.
Sources: src/traits.rs(L3 - L19)
The WeakRef Trait
The WeakRef trait defines an interface for types that represent weak references to heap-allocated values. A weak reference does not keep the referenced value alive; it can be used to access the value only if it's still alive due to strong references elsewhere.
#![allow(unused)] fn main() { pub trait WeakRef { type Strong: StrongRef<Weak = Self>; fn upgrade(&self) -> Option<Self::Strong>; fn is_expired(&self) -> bool { self.upgrade().is_none() } } }
The trait requires:
| Member | Type | Purpose |
|---|---|---|
| Strong | Associated type | Specifies the corresponding strong reference type |
| upgrade() | Method | Attempts to convert a weak reference to a strong reference |
| is_expired() | Method | Checks if the weak reference is expired (has default implementation) |
The Strong associated type complements the Weak type in StrongRef, creating a bidirectional relationship between the two traits.
Sources: src/traits.rs(L21 - L40)
Trait Implementations
The library provides implementations of these traits for standard Rust reference-counting types. This allows WeakMap to work with both single-threaded and thread-safe reference types.
flowchart TD
subgraph subGraph2["Thread-safe RC"]
Arc["std::sync::Arc<T>"]
ArcWeak["std::sync::Weak<T>"]
end
subgraph subGraph1["Single-threaded RC"]
Rc["std::rc::Rc<T>"]
RcWeak["std::rc::Weak<T>"]
end
subgraph subGraph0["Reference Traits"]
S["StrongRef Trait"]
W["WeakRef Trait"]
end
Arc --> ArcWeak
ArcWeak --> Arc
Rc --> RcWeak
RcWeak --> Rc
S --> Arc
S --> Rc
W --> ArcWeak
W --> RcWeak
Sources: src/traits.rs(L42 - L88)
Implementation for std::rc
For single-threaded reference counting, the traits are implemented for std::rc::Rc<T> and std::rc::Weak<T>:
| Type | Trait | Implementation Details |
|---|---|---|
| Rc | StrongRef | UsesRc::downgradeandRc::ptr_eq |
| Weak | WeakRef | UsesWeak::upgradeand customis_expiredthat checksstrong_count |
The is_expired implementation for Weak<T> optimizes the check by directly using strong_count() == 0 instead of trying to upgrade the reference.
Sources: src/traits.rs(L42 - L64)
Implementation for std::sync
For thread-safe reference counting, the traits are implemented for std::sync::Arc<T> and std::sync::Weak<T>:
| Type | Trait | Implementation Details |
|---|---|---|
| Arc | StrongRef | UsesArc::downgradeandArc::ptr_eq |
| Weak | WeakRef | UsesWeak::upgradeand customis_expiredthat checksstrong_count |
Similar to the std::rc implementation, the is_expired implementation for std::sync::Weak<T> directly checks the strong count for efficiency.
Sources: src/traits.rs(L66 - L88)
Reference Traits in Action
The reference traits enable WeakMap to work with different reference types in a generic way. Here's how these traits are used in the workflow of WeakMap:
sequenceDiagram
participant Client as Client
participant WeakMap as WeakMap
participant StrongRef as StrongRef
participant WeakRef as WeakRef
Client ->> WeakMap: insert(key, strong_ref)
WeakMap ->> StrongRef: downgrade()
StrongRef -->> WeakMap: weak_ref
WeakMap ->> WeakMap: store(key, weak_ref)
Client ->> WeakMap: get(key)
WeakMap ->> WeakMap: retrieve weak_ref
WeakMap ->> WeakRef: upgrade()
alt Value still alive
WeakRef -->> WeakMap: Some(strong_ref)
WeakMap -->> Client: Some(strong_ref)
else Value dropped
WeakRef -->> WeakMap: None
WeakMap -->> Client: None
end
Client ->> WeakMap: cleanup()
loop for each entry
WeakMap ->> WeakRef: is_expired()
alt Expired
WeakRef -->> WeakMap: true
WeakMap ->> WeakMap: remove entry
else Not expired
WeakRef -->> WeakMap: false
end
end
The use of traits allows WeakMap to be generic over the specific reference type, supporting both Rc and Arc with the same implementation.
Sources: src/traits.rs(L3 - L40)
Type Relationships
The following diagram illustrates the relationships between the trait types and concrete implementations:
classDiagram
class StrongRef {
<<trait>>
type Weak
downgrade() -~ Self::Weak
ptr_eq(other: &Self) -~ bool
}
class WeakRef {
<<trait>>
type Strong
upgrade() -~ Option
is_expired() -~ bool
}
class Rc~T~ {
downgrade() -~ Weak
ptr_eq(other: &Rc) -~ bool
}
class Weak~T~ {
upgrade() -~ Option~
strong_count() -~ usize
}
class Arc~T~ {
downgrade() -~ Weak
ptr_eq(other: &Arc) -~ bool
}
class ArcWeak~T~ {
upgrade() -~ Option~
strong_count() -~ usize
}
StrongRef ..|> Rc : implements
StrongRef ..|> Arc : implements
Weak ..|> WeakRef : implements
ArcWeak ..|> Arc : implements
This abstraction allows the WeakMap implementation to remain independent of the specific reference type, supporting both Rc for single-threaded use cases and Arc for multi-threaded scenarios.
Sources: src/traits.rs(L42 - L88)
Summary
The reference traits (StrongRef and WeakRef) provide a flexible abstraction for working with different types of references in the weak-map library. By implementing these traits for standard Rust reference types (Rc/Weak and Arc/Weak), the library allows for generic handling of references while maintaining the ability to use weak references that don't prevent values from being garbage collected.
These traits are fundamental to the operation of WeakMap, enabling it to store weak references to values and automatically clean up entries when the referenced values are dropped.