Skip to content

Instantly share code, notes, and snippets.

@bwatts
Last active January 28, 2023 20:41
Show Gist options
  • Save bwatts/bb4ccebd0fa6fdb288dc643f2b9b583a to your computer and use it in GitHub Desktop.
Save bwatts/bb4ccebd0fa6fdb288dc643f2b9b583a to your computer and use it in GitHub Desktop.
I got annoyed checking if counts are non-negative in every message.
[JsonConverter(typeof(Count32JsonConverter))]
[TypeConverter(typeof(Count32TypeConverter))]
public readonly struct Count32 : IEquatable<Count32>, IEquatable<int>, IComparable<Count32>, IComparable<int>
{
readonly int _value;
Count32(int value) =>
_value = value;
public override string ToString() =>
_value.ToString();
public int ToInt32() =>
_value;
public override int GetHashCode() =>
_value.GetHashCode();
public override bool Equals(object? obj) =>
obj switch
{
Count32 other => Equals(other),
int other => Equals(other),
_ => false
};
public bool Equals(Count32 other) =>
_value == other._value;
public bool Equals(int other) =>
_value == other;
public int CompareTo(Count32 other) =>
_value.CompareTo(other._value);
public int CompareTo(int other) =>
_value.CompareTo(other);
//
// Static API
//
public static bool TryFrom(int value, out Count32 count)
{
if(value >= 0)
{
count = new(value);
return true;
}
count = default;
return false;
}
public static Count32 From(int value) =>
TryFrom(value, out var count) ? count : throw new ArgumentOutOfRangeException(nameof(value));
public static bool operator ==(Count32 x, Count32 y) => EqualityComparer<Count32>.Default.Equals(x, y);
public static bool operator !=(Count32 x, Count32 y) => !(x == y);
public static bool operator <(Count32 x, Count32 y) => Comparer<Count32>.Default.Compare(x, y) < 0;
public static bool operator >(Count32 x, Count32 y) => Comparer<Count32>.Default.Compare(x, y) > 0;
public static bool operator <=(Count32 x, Count32 y) => Comparer<Count32>.Default.Compare(x, y) <= 0;
public static bool operator >=(Count32 x, Count32 y) => Comparer<Count32>.Default.Compare(x, y) >= 0;
public static bool operator ==(Count32 x, int y) => EqualityComparer<int>.Default.Equals(x._value, y);
public static bool operator !=(Count32 x, int y) => !(x == y);
public static bool operator <(Count32 x, int y) => Comparer<int>.Default.Compare(x._value, y) < 0;
public static bool operator >(Count32 x, int y) => Comparer<int>.Default.Compare(x._value, y) > 0;
public static bool operator <=(Count32 x, int y) => Comparer<int>.Default.Compare(x._value, y) <= 0;
public static bool operator >=(Count32 x, int y) => Comparer<int>.Default.Compare(x._value, y) >= 0;
public static explicit operator Count32(int value) => From(value);
public static implicit operator int(Count32 value) => value.ToInt32();
//
// Converters
//
sealed class Count32JsonConverter : JsonConverter<Count32>
{
public override Count32 Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) =>
TryFrom(reader.GetInt32(), out var count) ? count : default;
public override void Write(Utf8JsonWriter writer, Count32 value, JsonSerializerOptions options) =>
writer.WriteNumberValue(value.ToInt32());
}
sealed class Count32TypeConverter : TypeConverter
{
public override bool CanConvertFrom(ITypeDescriptorContext? context, Type sourceType) =>
sourceType == typeof(string);
public override bool CanConvertTo(ITypeDescriptorContext? context, Type? destinationType) =>
destinationType == typeof(string);
public override object? ConvertFrom(ITypeDescriptorContext? context, CultureInfo? culture, object value) =>
value is int i ? From(i) : base.ConvertFrom(context, culture, value);
public override object? ConvertTo(ITypeDescriptorContext? context, CultureInfo? culture, object? value, Type destinationType) =>
destinationType == typeof(int) && value is Count32 count
? count.ToString()
: base.ConvertTo(context, culture, value, destinationType);
}
}
[JsonConverter(typeof(Count64JsonConverter))]
[TypeConverter(typeof(Count64TypeConverter))]
public readonly struct Count64 : IEquatable<Count64>, IEquatable<long>, IComparable<Count64>, IComparable<long>
{
readonly long _value;
Count64(long value) =>
_value = value;
public override string ToString() =>
_value.ToString();
public long Tolong64() =>
_value;
public override int GetHashCode() =>
_value.GetHashCode();
public override bool Equals(object? obj) =>
obj switch
{
Count64 other => Equals(other),
long other => Equals(other),
_ => false
};
public bool Equals(Count64 other) =>
_value == other._value;
public bool Equals(long other) =>
_value == other;
public long CompareTo(Count64 other) =>
_value.CompareTo(other._value);
public long CompareTo(long other) =>
_value.CompareTo(other);
//
// Static API
//
public static bool TryFrom(long value, out Count64 count)
{
if(value >= 0)
{
count = new(value);
return true;
}
count = default;
return false;
}
public static Count64 From(long value) =>
TryFrom(value, out var count) ? count : throw new ArgumentOutOfRangeException(nameof(value));
public static bool operator ==(Count64 x, Count64 y) => EqualityComparer<Count64>.Default.Equals(x, y);
public static bool operator !=(Count64 x, Count64 y) => !(x == y);
public static bool operator <(Count64 x, Count64 y) => Comparer<Count64>.Default.Compare(x, y) < 0;
public static bool operator >(Count64 x, Count64 y) => Comparer<Count64>.Default.Compare(x, y) > 0;
public static bool operator <=(Count64 x, Count64 y) => Comparer<Count64>.Default.Compare(x, y) <= 0;
public static bool operator >=(Count64 x, Count64 y) => Comparer<Count64>.Default.Compare(x, y) >= 0;
public static bool operator ==(Count64 x, long y) => EqualityComparer<long>.Default.Equals(x._value, y);
public static bool operator !=(Count64 x, long y) => !(x == y);
public static bool operator <(Count64 x, long y) => Comparer<long>.Default.Compare(x._value, y) < 0;
public static bool operator >(Count64 x, long y) => Comparer<long>.Default.Compare(x._value, y) > 0;
public static bool operator <=(Count64 x, long y) => Comparer<long>.Default.Compare(x._value, y) <= 0;
public static bool operator >=(Count64 x, long y) => Comparer<long>.Default.Compare(x._value, y) >= 0;
public static explicit operator Count64(long value) => From(value);
public static implicit operator long(Count64 value) => value.Tolong64();
//
// Converters
//
sealed class Count64JsonConverter : JsonConverter<Count64>
{
public override Count64 Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) =>
TryFrom(reader.GetInt64(), out var count) ? count : default;
public override void Write(Utf8JsonWriter writer, Count64 value, JsonSerializerOptions options) =>
writer.WriteNumberValue(value.Tolong64());
}
sealed class Count64TypeConverter : TypeConverter
{
public override bool CanConvertFrom(ITypeDescriptorContext? context, Type sourceType) =>
sourceType == typeof(string);
public override bool CanConvertTo(ITypeDescriptorContext? context, Type? destinationType) =>
destinationType == typeof(string);
public override object? ConvertFrom(ITypeDescriptorContext? context, CultureInfo? culture, object value) =>
value is long i ? From(i) : base.ConvertFrom(context, culture, value);
public override object? ConvertTo(ITypeDescriptorContext? context, CultureInfo? culture, object? value, Type destinationType) =>
destinationType == typeof(long) && value is Count64 count
? count.ToString()
: base.ConvertTo(context, culture, value, destinationType);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment