11using System . Globalization ;
2+ using System . Text . Json . Serialization ;
23
34namespace Volte . Entities ;
45
6+
57public readonly record struct Snowflake ( ulong Raw ) : IComparable < Snowflake > , IComparable , IParsable < Snowflake >
68{
79 public int CompareTo ( Snowflake other ) => Raw . CompareTo ( other . Raw ) ;
@@ -20,15 +22,16 @@ public int CompareTo(object obj)
2022
2123 public DateTimeOffset Date => SnowflakeUtils . FromSnowflake ( Raw ) ;
2224
25+ public override string ToString ( ) => Raw . ToString ( ) ;
2326 public static implicit operator Snowflake ( ulong raw ) => new ( raw ) ;
2427 public static implicit operator ulong ( Snowflake snowflake ) => snowflake . Raw ;
2528 public static implicit operator Snowflake ( DateTimeOffset dto ) => FromDate ( dto ) ;
2629 public static implicit operator DateTimeOffset ( Snowflake snowflake ) => snowflake . Date ;
2730 public static implicit operator Snowflake ( DateTime dto ) => FromDate ( dto ) ;
2831 public static implicit operator DateTime ( Snowflake snowflake ) => snowflake . Date . DateTime ;
29-
32+
3033 public static Snowflake Zero { get ; set ; } = default ;
31-
34+
3235 public static Snowflake FromDate ( DateTimeOffset dto ) => new ( SnowflakeUtils . ToSnowflake ( dto ) ) ;
3336
3437 public static Snowflake ? TryParse ( string value , IFormatProvider formatProvider = null )
@@ -46,32 +49,44 @@ public int CompareTo(object obj)
4649
4750 return null ;
4851 }
49-
50- public static Snowflake Parse ( string s , IFormatProvider provider ) =>
51- TryParse ( s , provider , out var result )
52- ? result
53- : throw new ArgumentException ( $ "'{ s } ' did not contain a valid 64-bit unsigned integer or DateTimeOffset.") ;
52+
53+ public static Snowflake Parse ( string s , IFormatProvider provider )
54+ => TryParse ( s , provider )
55+ ?? throw new ArgumentException ( $ "'{ s } ' did not contain a valid 64-bit unsigned integer or DateTimeOffset.") ;
5456
5557 public static bool TryParse ( string s , IFormatProvider provider , out Snowflake result )
5658 {
57- result = Zero ;
58- if ( string . IsNullOrWhiteSpace ( s ) )
59- return false ;
59+ var res = TryParse ( s , provider ) ;
60+ result = res ?? Zero ;
6061
61- // As number
62- if ( ulong . TryParse ( s , NumberStyles . None , provider , out var number ) )
63- {
64- result = new Snowflake ( number ) ;
65- return true ;
66- }
62+ return res . HasValue ;
63+ }
6764
68- // As date
69- if ( DateTimeOffset . TryParse ( s , provider , DateTimeStyles . None , out var dto ) )
65+ public static bool TryParse ( string s , out Snowflake result )
66+ {
67+ var res = TryParse ( s ) ;
68+ result = res ?? Zero ;
69+
70+ return res . HasValue ;
71+ }
72+
73+ public class JsonConverter : JsonConverter < Snowflake >
74+ {
75+ public override Snowflake Read ( ref Utf8JsonReader reader , Type typeToConvert , JsonSerializerOptions options )
7076 {
71- result = FromDate ( dto ) ;
72- return true ;
77+ switch ( reader . TokenType )
78+ {
79+ case JsonTokenType . String :
80+ return Parse ( reader . GetString ( ) ! , null ) ;
81+ case JsonTokenType . Number :
82+ return new Snowflake ( reader . GetUInt64 ( ) ) ;
83+ default :
84+ throw new InvalidOperationException (
85+ "Snowflake JSON value is expected to be a datetime/integer string or a raw integer. Prefer raw integers." ) ;
86+ }
7387 }
7488
75- return false ;
89+ public override void Write ( Utf8JsonWriter writer , Snowflake value , JsonSerializerOptions options )
90+ => writer . WriteNumberValue ( value . Raw ) ;
7691 }
7792}
0 commit comments