-
-
Notifications
You must be signed in to change notification settings - Fork 30
Expand file tree
/
Copy pathBNumber.cs
More file actions
167 lines (133 loc) · 4.83 KB
/
BNumber.cs
File metadata and controls
167 lines (133 loc) · 4.83 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
using System;
using System.IO;
using System.IO.Pipelines;
using System.Text;
namespace BencodeNET.Objects
{
/// <summary>
/// Represents a bencoded number (integer).
/// </summary>
/// <remarks>
/// The underlying value is a <see cref="long"/>.
/// </remarks>
public sealed class BNumber : BObject<long>, IComparable<BNumber>
{
private static readonly DateTime Epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
/// <summary>
/// The string-length of long.MaxValue. Longer strings cannot be parsed.
/// </summary>
internal const int MaxDigits = 19;
/// <summary>
/// The underlying value.
/// </summary>
public override long Value { get; }
/// <summary>
/// Create a <see cref="BNumber"/> from a <see cref="long"/>.
/// </summary>
public BNumber(long value)
{
Value = value;
}
/// <summary>
/// Create a <see cref="BNumber"/> from a <see cref="DateTime"/>.
/// </summary>
/// <remarks>
/// Bencode dates are stored in unix format (seconds since epoch).
/// </remarks>
public BNumber(DateTime? datetime)
{
Value = datetime?.Subtract(Epoch).Ticks / TimeSpan.TicksPerSecond ?? 0;
}
/// <inheritdoc/>
public override int GetSizeInBytes() => Value.DigitCount() + 2;
/// <inheritdoc/>
protected override void EncodeObject(Stream stream)
{
stream.Write('i');
stream.Write(Value);
stream.Write('e');
}
/// <inheritdoc/>
protected override void EncodeObject(PipeWriter writer)
{
var size = GetSizeInBytes();
var buffer = writer.GetSpan(size).Slice(0, size);
buffer[0] = (byte) 'i';
buffer = buffer.Slice(1);
Encoding.ASCII.GetBytes(Value.ToString().AsSpan(), buffer);
buffer[buffer.Length - 1] = (byte) 'e';
writer.Advance(size);
}
#pragma warning disable 1591
public static implicit operator int?(BNumber bint)
{
if (bint == null) return null;
return (int)bint.Value;
}
public static implicit operator long?(BNumber bint)
{
if (bint == null) return null;
return bint.Value;
}
public static implicit operator int(BNumber bint)
{
if (bint == null) throw new InvalidCastException();
return (int)bint.Value;
}
public static implicit operator long(BNumber bint)
{
if (bint == null) throw new InvalidCastException();
return bint.Value;
}
public static implicit operator bool(BNumber bint)
{
if (bint == null) throw new InvalidCastException();
return bint.Value > 0;
}
public static implicit operator DateTime?(BNumber number)
{
if (number == null) return null;
if (number.Value > int.MaxValue)
{
try
{
return Epoch.AddMilliseconds(number);
}
catch (ArgumentOutOfRangeException)
{
return Epoch;
}
}
return Epoch.AddSeconds(number);
}
public static implicit operator BNumber(int value) => new BNumber(value);
public static implicit operator BNumber(long value) => new BNumber(value);
public static implicit operator BNumber(bool value) => new BNumber(value ? 1 : 0);
public static implicit operator BNumber(DateTime? datetime) => new BNumber(datetime);
public static bool operator ==(BNumber bnumber, BNumber other)
{
return bnumber?.Value == other?.Value;
}
public static bool operator !=(BNumber bnumber, BNumber other) => !(bnumber == other);
public override bool Equals(object other)
{
var bnumber = other as BNumber;
return Value == bnumber?.Value;
}
/// <summary>
/// Returns the hash code for this instance.
/// </summary>
public override int GetHashCode() => Value.GetHashCode();
public int CompareTo(BNumber other)
{
if (other == null)
return 1;
return Value.CompareTo(other.Value);
}
public override string ToString() => Value.ToString();
public string ToString(string format) => Value.ToString(format);
public string ToString(IFormatProvider formatProvider) => Value.ToString(formatProvider);
public string ToString(string format, IFormatProvider formatProvider) => Value.ToString(format, formatProvider);
#pragma warning restore 1591
}
}