22
33use std:: collections:: HashMap ;
44
5+ use serde:: ser:: { SerializeMap , Serializer } ;
56use serde:: { Deserialize , Serialize } ;
67
78/// Response from the create snapshot endpoint.
@@ -23,14 +24,32 @@ pub struct SnapshotsManifest {
2324// Keep in sync with https://github.com/getsentry/sentry/blob/master/src/sentry/preprod/snapshots/manifest.py
2425/// Metadata for a single image in a snapshot manifest.
2526///
26- /// The `image_file_name`, `width`, and `height` fields are set by the CLI.
27- /// Any additional fields from a companion JSON sidecar file are included
28- /// via `extra` and flattened into the serialized output.
29- #[ derive( Debug , Serialize ) ]
27+ /// Serializes as a flat JSON object. User-provided sidecar fields are included
28+ /// first, then CLI-managed fields (`image_file_name`, `width`, `height`) are
29+ /// written last so they always take precedence — similar to TypeScript's
30+ /// `{ ...extras, image_file_name, width, height }`.
31+ #[ derive( Debug ) ]
3032pub struct ImageMetadata {
3133 pub image_file_name : String ,
3234 pub width : u32 ,
3335 pub height : u32 ,
34- #[ serde( flatten) ]
3536 pub extra : HashMap < String , serde_json:: Value > ,
3637}
38+
39+ impl Serialize for ImageMetadata {
40+ fn serialize < S : Serializer > ( & self , serializer : S ) -> Result < S :: Ok , S :: Error > {
41+ let mut map = serializer. serialize_map ( Some ( self . extra . len ( ) + 3 ) ) ?;
42+
43+ // Sidecar fields first (user-provided extras)
44+ for ( key, value) in & self . extra {
45+ map. serialize_entry ( key, value) ?;
46+ }
47+
48+ // CLI-managed fields last — these always win
49+ map. serialize_entry ( "image_file_name" , & self . image_file_name ) ?;
50+ map. serialize_entry ( "width" , & self . width ) ?;
51+ map. serialize_entry ( "height" , & self . height ) ?;
52+
53+ map. end ( )
54+ }
55+ }
0 commit comments