@@ -16,8 +16,7 @@ use std::str;
1616use std:: time:: SystemTime ;
1717
1818use self :: debugid:: { CodeId , DebugId } ;
19- use serde:: Serializer ;
20- use serde:: { Deserialize , Serialize } ;
19+ use serde:: { de, Deserialize , Deserializer , Serialize , Serializer } ;
2120use thiserror:: Error ;
2221use url:: Url ;
2322use uuid:: Uuid ;
@@ -1477,6 +1476,60 @@ into_context!(Trace, TraceContext);
14771476into_context ! ( Gpu , GpuContext ) ;
14781477into_context ! ( Profile , ProfileContext ) ;
14791478
1479+ const INFERABLE_CONTEXTS : & [ & str ] = & [
1480+ "device" , "os" , "runtime" , "app" , "browser" , "trace" , "gpu" , "profile" ,
1481+ ] ;
1482+
1483+ struct ContextsVisitor ;
1484+
1485+ impl < ' de > de:: Visitor < ' de > for ContextsVisitor {
1486+ type Value = Map < String , Context > ;
1487+
1488+ fn expecting ( & self , formatter : & mut fmt:: Formatter ) -> fmt:: Result {
1489+ formatter. write_str ( "contexts object" )
1490+ }
1491+
1492+ fn visit_map < A > ( self , mut access : A ) -> Result < Self :: Value , A :: Error >
1493+ where
1494+ A : de:: MapAccess < ' de > ,
1495+ {
1496+ let mut map: Map < String , Context > = Map :: new ( ) ;
1497+
1498+ while let Some ( ( key, mut value) ) = access. next_entry :: < String , Value > ( ) ? {
1499+ let typed_value = value
1500+ . as_object_mut ( )
1501+ . map ( |ctx| {
1502+ if !ctx. contains_key ( "type" ) {
1503+ let type_key = if INFERABLE_CONTEXTS . contains ( & key. as_str ( ) ) {
1504+ key. clone ( ) . into ( )
1505+ } else {
1506+ Value :: String ( "unknown" . into ( ) )
1507+ } ;
1508+ ctx. insert ( String :: from ( "type" ) , type_key) ;
1509+ }
1510+ ctx. to_owned ( )
1511+ } )
1512+ . ok_or_else ( || de:: Error :: custom ( "expected valid `context` object" ) ) ?;
1513+
1514+ match serde_json:: from_value ( serde_json:: to_value ( typed_value) . unwrap ( ) ) {
1515+ Ok ( context) => {
1516+ map. insert ( key, context) ;
1517+ }
1518+ Err ( e) => return Err ( de:: Error :: custom ( e. to_string ( ) ) ) ,
1519+ }
1520+ }
1521+
1522+ Ok ( map)
1523+ }
1524+ }
1525+
1526+ fn deserialize_contexts < ' de , D > ( deserializer : D ) -> Result < Map < String , Context > , D :: Error >
1527+ where
1528+ D : Deserializer < ' de > ,
1529+ {
1530+ deserializer. deserialize_map ( ContextsVisitor { } )
1531+ }
1532+
14801533mod event {
14811534 use super :: * ;
14821535
@@ -1578,7 +1631,11 @@ pub struct Event<'a> {
15781631 #[ serde( default , skip_serializing_if = "Option::is_none" ) ]
15791632 pub request : Option < Request > ,
15801633 /// Optional contexts.
1581- #[ serde( default , skip_serializing_if = "Map::is_empty" ) ]
1634+ #[ serde(
1635+ default ,
1636+ skip_serializing_if = "Map::is_empty" ,
1637+ deserialize_with = "deserialize_contexts"
1638+ ) ]
15821639 pub contexts : Map < String , Context > ,
15831640 /// List of breadcrumbs to send along.
15841641 #[ serde( default , skip_serializing_if = "Values::is_empty" ) ]
@@ -1943,7 +2000,11 @@ pub struct Transaction<'a> {
19432000 /// The collection of finished spans part of this transaction.
19442001 pub spans : Vec < Span > ,
19452002 /// Optional contexts.
1946- #[ serde( default , skip_serializing_if = "Map::is_empty" ) ]
2003+ #[ serde(
2004+ default ,
2005+ skip_serializing_if = "Map::is_empty" ,
2006+ deserialize_with = "deserialize_contexts"
2007+ ) ]
19472008 pub contexts : Map < String , Context > ,
19482009 /// Optionally HTTP request data to be sent along.
19492010 #[ serde( default , skip_serializing_if = "Option::is_none" ) ]
0 commit comments