@@ -26,6 +26,7 @@ struct SizeState {
2626/// This means that large attributes will be trimmed or discarded before small ones.
2727#[ derive( Default ) ]
2828pub struct TrimmingProcessor {
29+ max_item_size : Option < usize > ,
2930 size_state : Vec < SizeState > ,
3031 /// Whether we are currently trimming a collection of attributes.
3132 /// This case needs to be distinguished for the purpose of accounting
@@ -35,8 +36,24 @@ pub struct TrimmingProcessor {
3536
3637impl TrimmingProcessor {
3738 /// Creates a new trimming processor.
38- pub fn new ( ) -> Self {
39- Self :: default ( )
39+ ///
40+ /// The `max_item_size` parameter is a global byte size
41+ /// limit for the item being processed.
42+ pub fn new ( max_item_size : Option < usize > ) -> Self {
43+ let mut size_state = Vec :: new ( ) ;
44+ if max_item_size. is_some ( ) {
45+ size_state. push ( SizeState {
46+ size_remaining : max_item_size,
47+ encountered_at_depth : 0 ,
48+ max_depth : None ,
49+ } ) ;
50+ }
51+
52+ Self {
53+ max_item_size,
54+ size_state,
55+ in_attributes : false ,
56+ }
4057 }
4158
4259 fn should_remove_container < T : Empty > ( & self , value : & T , state : & ProcessingState < ' _ > ) -> bool {
@@ -139,9 +156,7 @@ impl Processor for TrimmingProcessor {
139156 return Ok ( ( ) ) ;
140157 }
141158
142- if let Some ( size_state) = self . size_state . last ( )
143- && let Some ( size_remaining) = size_state. size_remaining
144- {
159+ if let Some ( size_remaining) = self . remaining_size ( ) {
145160 crate :: trimming:: trim_string ( value, meta, size_remaining, 0 ) ;
146161 }
147162
@@ -307,10 +322,12 @@ mod tests {
307322
308323 #[ derive( Debug , Clone , Empty , IntoValue , FromValue , ProcessValue ) ]
309324 struct TestObject {
310- #[ metastructure( max_bytes = 40 , trim = true ) ]
311- attributes : Annotated < Attributes > ,
312325 #[ metastructure( max_chars = 10 , trim = true ) ]
313326 body : Annotated < String > ,
327+ // This should neither be trimmed nor factor into size calculations.
328+ number : Annotated < u64 > ,
329+ #[ metastructure( max_bytes = 40 , trim = true ) ]
330+ attributes : Annotated < Attributes > ,
314331 }
315332
316333 #[ test]
@@ -323,16 +340,19 @@ mod tests {
323340
324341 let mut value = Annotated :: new ( TestObject {
325342 attributes : Annotated :: new ( attributes) ,
343+ number : Annotated :: new ( 0 ) ,
326344 body : Annotated :: new ( "This is longer than allowed" . to_owned ( ) ) ,
327345 } ) ;
328346
329- let mut processor = TrimmingProcessor :: new ( ) ;
347+ let mut processor = TrimmingProcessor :: new ( None ) ;
330348
331349 let state = ProcessingState :: new_root ( Default :: default ( ) , [ ] ) ;
332350 processor:: process_value ( & mut value, & mut processor, & state) . unwrap ( ) ;
333351
334352 insta:: assert_json_snapshot!( SerializableAnnotated ( & value) , @r###"
335353 {
354+ "body": "This is...",
355+ "number": 0,
336356 "attributes": {
337357 "medium string": {
338358 "type": "string",
@@ -343,7 +363,6 @@ mod tests {
343363 "value": 17
344364 }
345365 },
346- "body": "This is...",
347366 "_meta": {
348367 "attributes": {
349368 "": {
@@ -394,16 +413,19 @@ mod tests {
394413
395414 let mut value = Annotated :: new ( TestObject {
396415 attributes : Annotated :: new ( attributes) ,
416+ number : Annotated :: new ( 0 ) ,
397417 body : Annotated :: new ( "This is longer than allowed" . to_owned ( ) ) ,
398418 } ) ;
399419
400- let mut processor = TrimmingProcessor :: new ( ) ;
420+ let mut processor = TrimmingProcessor :: new ( None ) ;
401421
402422 let state = ProcessingState :: new_root ( Default :: default ( ) , [ ] ) ;
403423 processor:: process_value ( & mut value, & mut processor, & state) . unwrap ( ) ;
404424
405425 insta:: assert_json_snapshot!( SerializableAnnotated ( & value) , @r###"
406426 {
427+ "body": "This is...",
428+ "number": 0,
407429 "attributes": {
408430 "medium attribute": {
409431 "type": "string",
@@ -414,7 +436,6 @@ mod tests {
414436 "value": 17
415437 }
416438 },
417- "body": "This is...",
418439 "_meta": {
419440 "attributes": {
420441 "": {
@@ -466,16 +487,19 @@ mod tests {
466487
467488 let mut value = Annotated :: new ( TestObject {
468489 attributes : Annotated :: new ( attributes) ,
490+ number : Annotated :: new ( 0 ) ,
469491 body : Annotated :: new ( "This is longer than allowed" . to_owned ( ) ) ,
470492 } ) ;
471493
472- let mut processor = TrimmingProcessor :: new ( ) ;
494+ let mut processor = TrimmingProcessor :: new ( None ) ;
473495
474496 let state = ProcessingState :: new_root ( Default :: default ( ) , [ ] ) ;
475497 processor:: process_value ( & mut value, & mut processor, & state) . unwrap ( ) ;
476498
477499 insta:: assert_json_snapshot!( SerializableAnnotated ( & value) , @r###"
478500 {
501+ "body": "This is...",
502+ "number": 0,
479503 "attributes": {
480504 "attribute with long name": {
481505 "type": "integer",
@@ -486,7 +510,6 @@ mod tests {
486510 "value": "abcdefgh"
487511 }
488512 },
489- "body": "This is...",
490513 "_meta": {
491514 "attributes": {
492515 "": {
@@ -510,4 +533,66 @@ mod tests {
510533 }
511534 "### ) ;
512535 }
536+
537+ #[ test]
538+ fn test_max_item_size ( ) {
539+ let mut attributes = Attributes :: new ( ) ;
540+
541+ attributes. insert ( "small" , 17 ) ; // 13B
542+ attributes. insert ( "medium string" , "This string should be trimmed" ) ; // 42B
543+ attributes. insert ( "attribute is very large and should be removed" , true ) ; // 47B
544+
545+ let mut value = Annotated :: new ( TestObject {
546+ attributes : Annotated :: new ( attributes) ,
547+ number : Annotated :: new ( 0 ) ,
548+ body : Annotated :: new ( "Short" . to_owned ( ) ) ,
549+ } ) ;
550+
551+ // The `body` takes up 5B, the `"small"` attribute 13B, and the key "medium string" another 13B.
552+ // That leaves 9B for the string's value.
553+ // Note that the `number` field doesn't take up any size.
554+ let mut processor = TrimmingProcessor :: new ( Some ( 40 ) ) ;
555+
556+ let state = ProcessingState :: new_root ( Default :: default ( ) , [ ] ) ;
557+ processor:: process_value ( & mut value, & mut processor, & state) . unwrap ( ) ;
558+
559+ insta:: assert_json_snapshot!( SerializableAnnotated ( & value) , @r###"
560+ {
561+ "body": "Short",
562+ "number": 0,
563+ "attributes": {
564+ "medium string": {
565+ "type": "string",
566+ "value": "This s..."
567+ },
568+ "small": {
569+ "type": "integer",
570+ "value": 17
571+ }
572+ },
573+ "_meta": {
574+ "attributes": {
575+ "": {
576+ "len": 101
577+ },
578+ "medium string": {
579+ "value": {
580+ "": {
581+ "rem": [
582+ [
583+ "!limit",
584+ "s",
585+ 6,
586+ 9
587+ ]
588+ ],
589+ "len": 29
590+ }
591+ }
592+ }
593+ }
594+ }
595+ }
596+ "### ) ;
597+ }
513598}
0 commit comments