1
1
use alloc:: borrow:: Cow ;
2
2
use alloc:: vec:: Vec ;
3
+ use serde:: de:: { IgnoredAny , VariantAccess , Visitor } ;
3
4
use serde:: Deserialize ;
4
5
5
6
use crate :: util:: { deserialize_optional_string_to_i64, deserialize_string_to_i64} ;
@@ -13,24 +14,63 @@ use super::Checksum;
13
14
/// internal copy).
14
15
type SyncLineStr < ' a > = Cow < ' a , str > ;
15
16
16
- #[ derive( Deserialize , Debug ) ]
17
+ #[ derive( Debug ) ]
17
18
18
19
pub enum SyncLine < ' a > {
19
- #[ serde( rename = "checkpoint" , borrow) ]
20
20
Checkpoint ( Checkpoint < ' a > ) ,
21
- #[ serde( rename = "checkpoint_diff" , borrow) ]
22
21
CheckpointDiff ( CheckpointDiff < ' a > ) ,
23
-
24
- #[ serde( rename = "checkpoint_complete" ) ]
25
22
CheckpointComplete ( CheckpointComplete ) ,
26
- #[ serde( rename = "partial_checkpoint_complete" ) ]
27
23
CheckpointPartiallyComplete ( CheckpointPartiallyComplete ) ,
28
-
29
- #[ serde( rename = "data" , borrow) ]
30
24
Data ( DataLine < ' a > ) ,
31
-
32
- #[ serde( rename = "token_expires_in" ) ]
33
25
KeepAlive ( TokenExpiresIn ) ,
26
+ UnknownSyncLine ,
27
+ }
28
+
29
+ impl < ' de > Deserialize < ' de > for SyncLine < ' de > {
30
+ fn deserialize < D > ( deserializer : D ) -> Result < Self , D :: Error >
31
+ where
32
+ D : serde:: Deserializer < ' de > ,
33
+ {
34
+ struct SyncLineVisitor ;
35
+
36
+ impl < ' de > Visitor < ' de > for SyncLineVisitor {
37
+ type Value = SyncLine < ' de > ;
38
+
39
+ fn expecting ( & self , formatter : & mut core:: fmt:: Formatter ) -> core:: fmt:: Result {
40
+ write ! ( formatter, "a sync line" )
41
+ }
42
+
43
+ fn visit_enum < A > ( self , data : A ) -> Result < Self :: Value , A :: Error >
44
+ where
45
+ A : serde:: de:: EnumAccess < ' de > ,
46
+ {
47
+ let ( name, payload) = data. variant :: < & ' de str > ( ) ?;
48
+ Ok ( match name {
49
+ "checkpoint" => SyncLine :: Checkpoint ( payload. newtype_variant :: < Checkpoint > ( ) ?) ,
50
+ "checkpoint_diff" => {
51
+ SyncLine :: CheckpointDiff ( payload. newtype_variant :: < CheckpointDiff > ( ) ?)
52
+ }
53
+ "checkpoint_complete" => SyncLine :: CheckpointComplete (
54
+ payload. newtype_variant :: < CheckpointComplete > ( ) ?,
55
+ ) ,
56
+ "partial_checkpoint_complete" => SyncLine :: CheckpointPartiallyComplete (
57
+ payload. newtype_variant :: < CheckpointPartiallyComplete > ( ) ?,
58
+ ) ,
59
+ "data" => SyncLine :: Data ( payload. newtype_variant :: < DataLine > ( ) ?) ,
60
+ "token_expires_in" => {
61
+ SyncLine :: KeepAlive ( payload. newtype_variant :: < TokenExpiresIn > ( ) ?)
62
+ }
63
+ _ => {
64
+ payload. newtype_variant :: < IgnoredAny > ( ) ?;
65
+
66
+ SyncLine :: UnknownSyncLine
67
+ }
68
+ } )
69
+ }
70
+ }
71
+
72
+ deserializer. deserialize_enum ( "SyncLine" , & [ ] , SyncLineVisitor )
73
+ }
34
74
}
35
75
36
76
#[ derive( Deserialize , Debug ) ]
@@ -160,6 +200,8 @@ impl<'a, 'de: 'a> Deserialize<'de> for OplogData<'a> {
160
200
mod tests {
161
201
use core:: assert_matches:: assert_matches;
162
202
203
+ use alloc:: string:: ToString ;
204
+
163
205
use super :: * ;
164
206
165
207
fn deserialize ( source : & str ) -> SyncLine {
@@ -305,4 +347,16 @@ mod tests {
305
347
}
306
348
) ;
307
349
}
350
+
351
+ #[ test]
352
+ fn parse_unknown ( ) {
353
+ assert_matches ! ( deserialize( "{\" foo\" : {}}" ) , SyncLine :: UnknownSyncLine ) ;
354
+ assert_matches ! ( deserialize( "{\" foo\" : 123}" ) , SyncLine :: UnknownSyncLine ) ;
355
+ }
356
+
357
+ #[ test]
358
+ fn parse_invalid_duplicate_key ( ) {
359
+ let e = serde_json:: from_str :: < SyncLine > ( r#"{"foo": {}, "bar": {}}"# ) . unwrap_err ( ) ;
360
+ assert_eq ! ( e. to_string( ) , "expected value at line 1 column 10" ) ;
361
+ }
308
362
}
0 commit comments