Fauna v10 .NET/C# Driver 0.2.0-beta
 
Loading...
Searching...
No Matches
Utf8FaunaReader.cs
Go to the documentation of this file.
1using System.Buffers;
2using System.Globalization;
3using System.Text;
4using System.Text.Json;
5using Fauna.Types;
7
8namespace Fauna.Serialization;
9
13public ref struct Utf8FaunaReader
14{
15 private Utf8JsonReader _json;
16 private readonly Stack<object> _tokenStack = new();
17 private TokenType? _bufferedTokenType = null;
18
19 private readonly HashSet<TokenType> _closers = new()
20 {
21 TokenType.EndObject,
22 TokenType.EndPage,
23 TokenType.EndDocument,
24 TokenType.EndRef,
25 TokenType.EndArray
26 };
27
28 private string? _taggedTokenValue = null;
29
33 public TokenType CurrentTokenType { get; private set; }
34
35 private enum TokenTypeInternal
36 {
38 StartEscapedObject,
39 }
40
45 public Utf8FaunaReader(ReadOnlySequence<byte> bytes)
46 {
47 _json = new Utf8JsonReader(bytes);
49 }
50
55 public Utf8FaunaReader(string str)
56 {
57 var bytes = Encoding.UTF8.GetBytes(str);
58 var seq = new ReadOnlySequence<byte>(bytes);
59 _json = new Utf8JsonReader(seq);
61 }
62
66 public void Skip()
67 {
68 switch (CurrentTokenType)
69 {
70 case TokenType.StartObject:
71 case TokenType.StartArray:
72 case TokenType.StartPage:
73 case TokenType.StartRef:
74 case TokenType.StartDocument:
75 SkipInternal();
76 break;
77 }
78 }
79
80 private void SkipInternal()
81 {
82 var startCount = _tokenStack.Count;
83 while (Read())
84 {
85 if (_tokenStack.Count < startCount) break;
86 }
87 }
88
93 public bool Read()
94 {
95 _taggedTokenValue = null;
96
97 if (_bufferedTokenType != null)
98 {
99 CurrentTokenType = (TokenType)_bufferedTokenType;
100 _bufferedTokenType = null;
101 if (_closers.Contains(CurrentTokenType))
102 {
103 _tokenStack.Pop();
104 }
105 return true;
106 }
107
108 if (!Advance())
109 {
110 return false;
111 }
112
113 switch (_json.TokenType)
114 {
115 case JsonTokenType.PropertyName:
116 CurrentTokenType = TokenType.FieldName;
117 break;
118 case JsonTokenType.None:
119 break;
120 case JsonTokenType.StartObject:
121 HandleStartObject();
122 break;
123 case JsonTokenType.EndObject:
124 HandleEndObject();
125 break;
126 case JsonTokenType.StartArray:
127 _tokenStack.Push(TokenType.StartArray);
128 CurrentTokenType = TokenType.StartArray;
129 break;
130 case JsonTokenType.EndArray:
131 _tokenStack.Pop();
132 CurrentTokenType = TokenType.EndArray;
133 break;
134 case JsonTokenType.String:
136 break;
137 case JsonTokenType.True:
139 break;
140 case JsonTokenType.False:
142 break;
143 case JsonTokenType.Null:
145 break;
146 case JsonTokenType.Comment:
147 case JsonTokenType.Number:
148 default:
149 throw new SerializationException($"Unhandled JSON token type {_json.TokenType}.");
150 }
151
152 return true;
153 }
154
160 public object? GetValue()
161 {
162 return CurrentTokenType switch
163 {
164 TokenType.FieldName or TokenType.String => GetString(),
165 TokenType.Int => GetInt(),
166 TokenType.Long => GetLong(),
167 TokenType.Double => GetDouble(),
168 TokenType.Date => GetDate(),
169 TokenType.Time => GetTime(),
170 TokenType.True or TokenType.False => GetBoolean(),
171 TokenType.Module => GetModule(),
172 _ => throw new SerializationException($"{CurrentTokenType} does not have an associated value")
173 };
174 }
175
180 public string? GetString()
181 {
182 if (CurrentTokenType != TokenType.String && CurrentTokenType != TokenType.FieldName)
183 {
184 throw new InvalidOperationException($"Fauna token value isn't a {TokenType.String.ToString()} or a {TokenType.FieldName.ToString()}.");
185 }
186
187 try
188 {
189 return _json.GetString();
190 }
191 catch (Exception e)
192 {
193 throw new SerializationException("Failed to get string", e);
194 }
195 }
196
201 public bool GetBoolean()
202 {
203 try
204 {
205 return _json.GetBoolean();
206 }
207 catch (Exception e)
208 {
209 throw new SerializationException("Failed to get boolean", e);
210 }
211 }
212
217 public DateOnly GetDate()
218 {
219 ValidateTaggedType(TokenType.Date);
220
221 try
222 {
223 return DateOnly.Parse(_taggedTokenValue!);
224 }
225 catch (Exception e)
226 {
227 throw new SerializationException($"Failed to get date from {_taggedTokenValue}", e);
228 }
229 }
230
235 public float GetFloat()
236 {
237 ValidateTaggedTypes(TokenType.Int, TokenType.Long, TokenType.Double);
238
239 try
240 {
241 return float.Parse(_taggedTokenValue!, CultureInfo.InvariantCulture);
242 }
243 catch (Exception e)
244 {
245 throw new SerializationException($"Failed to get float from {_taggedTokenValue}", e);
246 }
247 }
248
253 public double GetDouble()
254 {
255 ValidateTaggedTypes(TokenType.Int, TokenType.Long, TokenType.Double);
256
257 try
258 {
259 return double.Parse(_taggedTokenValue!, CultureInfo.InvariantCulture);
260 }
261 catch (Exception e)
262 {
263 throw new SerializationException($"Failed to get double from {_taggedTokenValue}", e);
264 }
265 }
266
271 public decimal GetDoubleAsDecimal()
272 {
273 ValidateTaggedType(TokenType.Double);
274
275 try
276 {
277 return decimal.Parse(_taggedTokenValue!, CultureInfo.InvariantCulture);
278 }
279 catch (Exception e)
280 {
281 throw new SerializationException($"Failed to get decimal from {_taggedTokenValue}", e);
282 }
283 }
284
289 public byte GetByte()
290 {
291 ValidateTaggedTypes(TokenType.Int);
292
293 try
294 {
295 return byte.Parse(_taggedTokenValue!);
296 }
297 catch (Exception e)
298 {
299 throw new SerializationException($"Failed to get byte from {_taggedTokenValue}", e);
300 }
301 }
302
307 public sbyte GetUnsignedByte()
308 {
309 ValidateTaggedTypes(TokenType.Int);
310
311 try
312 {
313 return sbyte.Parse(_taggedTokenValue!);
314 }
315 catch (Exception e)
316 {
317 throw new SerializationException($"Failed to get sbyte from {_taggedTokenValue}", e);
318 }
319 }
320
325 public int GetInt()
326 {
327 ValidateTaggedTypes(TokenType.Int, TokenType.Long);
328
329 try
330 {
331 return int.Parse(_taggedTokenValue!);
332 }
333 catch (Exception e)
334 {
335 throw new SerializationException($"Failed to get int from {_taggedTokenValue}", e);
336 }
337 }
338
343 public uint GetUnsignedInt()
344 {
345 ValidateTaggedTypes(TokenType.Int, TokenType.Long);
346
347 try
348 {
349 return uint.Parse(_taggedTokenValue!);
350 }
351 catch (Exception e)
352 {
353 throw new SerializationException($"Failed to get uint from {_taggedTokenValue}", e);
354 }
355 }
356
361 public short GetShort()
362 {
363 ValidateTaggedTypes(TokenType.Int, TokenType.Long);
364 try
365 {
366 return short.Parse(_taggedTokenValue!);
367 }
368 catch (Exception e)
369 {
370 throw new SerializationException($"Failed to get short from {_taggedTokenValue}", e);
371 }
372 }
373
378 public ushort GetUnsignedShort()
379 {
380 ValidateTaggedTypes(TokenType.Int, TokenType.Long);
381 try
382 {
383 return ushort.Parse(_taggedTokenValue!);
384 }
385 catch (Exception e)
386 {
387 throw new SerializationException($"Failed to get ushort from {_taggedTokenValue}", e);
388 }
389 }
390
395 public long GetLong()
396 {
397 ValidateTaggedTypes(TokenType.Int, TokenType.Long);
398
399 try
400 {
401 return long.Parse(_taggedTokenValue!);
402 }
403 catch (Exception e)
404 {
405 throw new SerializationException($"Failed to get long from {_taggedTokenValue}", e);
406 }
407 }
408
414 {
415 ValidateTaggedType(TokenType.Module);
416
417 return new Module(_taggedTokenValue!);
418 }
419
425 {
426 ValidateTaggedType(TokenType.Stream);
427
428 return new Stream(_taggedTokenValue!);
429 }
430
435 public DateTime GetTime()
436 {
437 ValidateTaggedType(TokenType.Time);
438
439 try
440 {
441 return DateTime.Parse(_taggedTokenValue!);
442 }
443 catch (Exception e)
444 {
445 throw new SerializationException($"Failed to get time from {_taggedTokenValue}", e);
446 }
447 }
448
454 public string TryGetString(out string value)
455 {
456 throw new NotImplementedException();
457 }
458
464 public bool TryGetBoolean(out bool value)
465 {
466 throw new NotImplementedException();
467 }
468
474 public DateTime TryGetDateTime(out DateTime value)
475 {
476 throw new NotImplementedException();
477 }
478
484 public double TryGetDouble(out double value)
485 {
486 throw new NotImplementedException();
487 }
488
494 public int TryGetInt(out int value)
495 {
496 throw new NotImplementedException();
497 }
498
504 public long TryGetLong(out long value)
505 {
506 throw new NotImplementedException();
507 }
508
514 public Module TryGetModule(out Module value)
515 {
516 throw new NotImplementedException();
517 }
518
519 private void ValidateTaggedType(TokenType type)
520 {
521 if (CurrentTokenType != type || _taggedTokenValue == null || _taggedTokenValue.GetType() != typeof(string))
522 {
523 throw new InvalidOperationException($"CurrentTokenType is a {CurrentTokenType.ToString()}, not a {type.ToString()}.");
524 }
525 }
526
527 private void ValidateTaggedTypes(params TokenType[] types)
528 {
529 if (!types.Contains(CurrentTokenType) || _taggedTokenValue == null || _taggedTokenValue.GetType() != typeof(string))
530 {
531 throw new InvalidOperationException($"CurrentTokenType is a {CurrentTokenType.ToString()}, not in {types}.");
532 }
533 }
534
535
536 private void HandleStartObject()
537 {
538 AdvanceTrue();
539
540 switch (_json.TokenType)
541 {
542 case JsonTokenType.PropertyName:
543 switch (_json.GetString())
544 {
545 case "@date":
546 HandleTaggedString(TokenType.Date);
547 break;
548 case "@doc":
549 AdvanceTrue();
550 CurrentTokenType = TokenType.StartDocument;
551 _tokenStack.Push(TokenType.StartDocument);
552 break;
553 case "@double":
554 HandleTaggedString(TokenType.Double);
555 break;
556 case "@int":
557 HandleTaggedString(TokenType.Int);
558 break;
559 case "@long":
560 HandleTaggedString(TokenType.Long);
561 break;
562 case "@mod":
563 HandleTaggedString(TokenType.Module);
564 break;
565 case "@stream":
566 HandleTaggedString(TokenType.Stream);
567 break;
568 case "@object":
569 AdvanceTrue();
570 CurrentTokenType = TokenType.StartObject;
571 _tokenStack.Push(TokenTypeInternal.StartEscapedObject);
572 break;
573 case "@ref":
574 AdvanceTrue();
575 CurrentTokenType = TokenType.StartRef;
576 _tokenStack.Push(TokenType.StartRef);
577 break;
578 case "@set":
579 AdvanceTrue();
580 CurrentTokenType = TokenType.StartPage;
581 _tokenStack.Push(TokenType.StartPage);
582 break;
583 case "@time":
584 HandleTaggedString(TokenType.Time);
585 break;
586 default:
587 _bufferedTokenType = TokenType.FieldName;
588 _tokenStack.Push(TokenType.StartObject);
589 CurrentTokenType = TokenType.StartObject;
590 break;
591 }
592 break;
593 case JsonTokenType.EndObject:
594 _bufferedTokenType = TokenType.EndObject;
595 _tokenStack.Push(TokenType.StartObject);
596 CurrentTokenType = TokenType.StartObject;
597 break;
598 default:
599 throw new SerializationException($"Unexpected token following StartObject: {_json.TokenType}");
600 }
601 }
602
603 private void HandleEndObject()
604 {
605 var startToken = _tokenStack.Pop();
606 switch (startToken)
607 {
608 case TokenType.StartDocument:
609 CurrentTokenType = TokenType.EndDocument;
610 AdvanceTrue();
611 break;
612 case TokenType.StartPage:
613 CurrentTokenType = TokenType.EndPage;
614 AdvanceTrue();
615 break;
616 case TokenType.StartRef:
618 AdvanceTrue();
619 break;
620 case TokenTypeInternal.StartEscapedObject:
621 CurrentTokenType = TokenType.EndObject;
622 AdvanceTrue();
623 break;
624 case TokenType.StartObject:
625 CurrentTokenType = TokenType.EndObject;
626 break;
627 default:
628 throw new SerializationException($"Unexpected token {startToken}. This might be a bug.");
629 }
630 }
631
643 private void HandleTaggedString(TokenType token)
644 {
645 AdvanceTrue();
646 CurrentTokenType = token;
647 _taggedTokenValue = _json.GetString();
648 AdvanceTrue();
649 }
650
651 private bool Advance()
652 {
653 try
654 {
655 return _json.Read();
656 }
657 catch (Exception e)
658 {
659 throw new SerializationException("Failed to advance underlying JSON reader.", e);
660 }
661 }
662
663 private void AdvanceTrue()
664 {
665 if (!Advance())
666 {
667 throw new SerializationException("Unexpected end of underlying JSON reader.");
668 }
669 }
670}
Represents error that occur during serialization and deserialization of Fauna data.
Represents a module, a singleton object grouping related functionalities. Modules are serialized as @...
Definition Module.cs:8
Represents a Fauna stream token.
Definition Stream.cs:7
TokenType
Enumerates the types of tokens used in Fauna serialization.
Definition TokenType.cs:7
@ Module
The token type is the Fauna module.
@ Stream
The token type is the Fauna stream token.
Definition Client.cs:8
Represents a reader that provides fast, non-cached, forward-only access to serialized data.
Utf8FaunaReader(ReadOnlySequence< byte > bytes)
Initializes a new Utf8FaunaReader to read from a ReadOnlySequence of bytes.
decimal GetDoubleAsDecimal()
Retrieves a decimal value from the current token.
DateOnly GetDate()
Retrieves a DateOnly value from the current token.
void Skip()
Skips the value of the current token.
DateTime TryGetDateTime(out DateTime value)
Tries to retrieve a DateTime value from the current token.
byte GetByte()
Retrieves an byte value from the current token.
Module TryGetModule(out Module value)
Tries to retrieve a Module object from the current token.
Stream GetStream()
Retrieves a Stream token string from the current token.
short GetShort()
Retrieves an short value from the current token.
long TryGetLong(out long value)
Tries to retrieve a long value from the current token.
double GetDouble()
Retrieves a double value from the current token.
Utf8FaunaReader(string str)
Initializes a new Utf8FaunaReader to read from a string.
string TryGetString(out string value)
Tries to retrieve a string value from the current token.
bool TryGetBoolean(out bool value)
Tries to retrieve a boolean value from the current token.
object? GetValue()
Gets the value of the current token.
TokenType CurrentTokenType
Gets the type of the current token.
int TryGetInt(out int value)
Tries to retrieve an integer value from the current token.
uint GetUnsignedInt()
Retrieves an unsigned integer value from the current token.
ushort GetUnsignedShort()
Retrieves an unsigned short value from the current token.
long GetLong()
Retrieves a long value from the current token.
bool GetBoolean()
Retrieves a boolean value from the current JSON token.
float GetFloat()
Retrieves a float value from the current token.
string? GetString()
Retrieves a string value from the current token.
bool Read()
Reads the next token from the source.
DateTime GetTime()
Retrieves a DateTime value from the current token.
double TryGetDouble(out double value)
Tries to retrieve a double value from the current token.
sbyte GetUnsignedByte()
Retrieves an unsigned byte value from the current token.
int GetInt()
Retrieves an integer value from the current token.
Module GetModule()
Retrieves a Module object from the current token.