@@ -96,31 +96,21 @@ impl Serialize for Report {
9696 }
9797}
9898
99- /// The Problem Report list
100- #[ derive( Clone ) ]
101- struct Context ( Arc < String > ) ;
102-
103- impl Serialize for Context {
104- fn serialize < S > ( & self , serializer : S ) -> Result < S :: Ok , S :: Error >
105- where S : serde:: Serializer {
106- let str = self . 0 . as_ref ( ) ;
107- serializer. serialize_str ( str)
108- }
109- }
110-
111- /// Problem Report
112- #[ derive( Clone , Serialize ) ]
113- pub struct ProblemReport {
99+ /// An inner state of the report.
100+ #[ derive( Serialize ) ]
101+ struct State {
114102 /// What context does the whole report have
115- context : Context ,
103+ context : String ,
116104 /// The report itself
117- // Note, we use this because it allows:
118- // 1. Cheap copy of this struct.
119- // 2. Ergonomic Inner mutability.
120- // 3. Safety for the Problem Report to be used across threads
121105 report : Report ,
122106}
123107
108+ /// Problem Report.
109+ ///
110+ /// This structure allows making a cheap copies that share the same state.
111+ #[ derive( Clone , Serialize ) ]
112+ pub struct ProblemReport ( Arc < State > ) ;
113+
124114impl ProblemReport {
125115 /// Creates a new `ProblemReport` with the given context string.
126116 ///
@@ -138,10 +128,11 @@ impl ProblemReport {
138128 /// ```
139129 #[ must_use]
140130 pub fn new ( context : & str ) -> Self {
141- Self {
142- context : Context ( Arc :: new ( context. to_string ( ) ) ) ,
131+ let state = State {
132+ context : context. to_owned ( ) ,
143133 report : Report ( ConcurrentVec :: new ( ) ) ,
144- }
134+ } ;
135+ Self ( Arc :: new ( state) )
145136 }
146137
147138 /// Determines if the problem report contains any issues.
@@ -164,12 +155,12 @@ impl ProblemReport {
164155 /// ```
165156 #[ must_use]
166157 pub fn is_problematic ( & self ) -> bool {
167- !self . report . 0 . is_empty ( )
158+ !self . 0 . report . 0 . is_empty ( )
168159 }
169160
170161 /// Add an entry to the report
171162 fn add_entry ( & self , kind : Kind , context : & str ) {
172- self . report . 0 . push ( Entry {
163+ self . 0 . report . 0 . push ( Entry {
173164 kind,
174165 context : context. to_owned ( ) ,
175166 } ) ;
@@ -459,3 +450,23 @@ impl ProblemReport {
459450 ) ;
460451 }
461452}
453+
454+ #[ cfg( test) ]
455+ mod tests {
456+ use super :: * ;
457+
458+ // Check that the Clone implementation performs the shallow copy, so all instances share
459+ // the same state.
460+ #[ test]
461+ fn clone_shared_state ( ) {
462+ let original = ProblemReport :: new ( "top level context" ) ;
463+ assert ! ( !original. is_problematic( ) ) ;
464+
465+ let clone = original. clone ( ) ;
466+ clone. other ( "description" , "error context" ) ;
467+ assert ! ( clone. is_problematic( ) ) ;
468+
469+ // The original report must have the same (problematic) state.
470+ assert ! ( original. is_problematic( ) ) ;
471+ }
472+ }
0 commit comments