• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

neon-sunset / U8String / 6005516171

28 Aug 2023 10:17PM UTC coverage: 17.791% (-0.3%) from 18.096%
6005516171

push

github

neon-sunset
feat: add construction overloads for streams and file handles

134 of 1066 branches covered (0.0%)

Branch coverage included in aggregate %.

97 of 97 new or added lines in 3 files covered. (100.0%)

478 of 2374 relevant lines covered (20.13%)

34680.8 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

8.43
/src/Implementations/Standard/U8String.Construction.cs
1
using System.Collections.Immutable;
2
using System.Diagnostics;
3
using System.Diagnostics.CodeAnalysis;
4
using System.Runtime.InteropServices;
5
using Microsoft.Win32.SafeHandles;
6
using U8Primitives.InteropServices;
7
using U8Primitives.IO;
8

9
namespace U8Primitives;
10

11
public readonly partial struct U8String
12
{
13
    /// <summary>
14
    /// Creates a new <see cref="U8String"/> from the specified UTF-8 bytes.
15
    /// </summary>
16
    /// <param name="value">The UTF-8 bytes to create the <see cref="U8String"/> from.</param>
17
    /// <exception cref="ArgumentException">Thrown when <paramref name="value"/> contains malformed UTF-8 data.</exception>
18
    /// <remarks>
19
    /// The <see cref="U8String"/> will be created by copying the <paramref name="value"/> bytes if the length is greater than 0.
20
    /// </remarks>
21
    public U8String(ReadOnlySpan<byte> value)
22
    {
23
        // Contract:
24
        // byte[] Value *must* remain null if the length is 0.
25
        if (value.Length > 0)
54✔
26
        {
27
            Validate(value);
45✔
28
            _value = value.ToArray();
45✔
29
            _inner = new U8Range(0, value.Length);
45✔
30
        }
31
    }
54✔
32

33
    /// <summary>
34
    /// Creates a new <see cref="U8String"/> from the specified <see cref="ImmutableArray{T}"/> of <see cref="byte"/>s.
35
    /// </summary>
36
    /// <param name="value">The <see cref="ImmutableArray{T}"/> of <see cref="byte"/>s to create the <see cref="U8String"/> from.</param>
37
    /// <exception cref="ArgumentException">Thrown when <paramref name="value"/> contains malformed UTF-8 data.</exception>
38
    /// <remarks>
39
    /// The <see cref="U8String"/> will be created by taking the underlying reference from the <paramref name="value"/> without copying if the length is greater than 0.
40
    /// </remarks>
41
    public U8String(ImmutableArray<byte> value)
42
    {
43
        var bytes = ImmutableCollectionsMarshal.AsArray(value);
×
44
        if (bytes?.Length > 0)
×
45
        {
46
            Validate(bytes);
×
47
            _value = bytes;
×
48
            _inner = new U8Range(0, bytes.Length);
×
49
        }
50
    }
×
51

52
    /// <summary>
53
    /// Creates a new <see cref="U8String"/> from the specified <see cref="ReadOnlySpan{T}"/> of UTF-8 <see cref="char"/>s.
54
    /// </summary>
55
    /// <param name="value">The <see cref="ReadOnlySpan{T}"/> of <see cref="char"/>s to create the <see cref="U8String"/> from.</param>
56
    /// <remarks>
57
    /// The <see cref="U8String"/> will be created by encoding the <see cref="char"/>s as UTF-8.
58
    /// </remarks>
59
    public U8String(ReadOnlySpan<char> value)
60
    {
61
        if (value.Length > 0)
×
62
        {
63
            this = Parse(value, null);
×
64
        }
65
    }
×
66

67
    /// <summary>
68
    /// Creates a new <see cref="U8String"/> from the specified <see cref="string"/>.
69
    /// </summary>
70
    /// <param name="value">The <see cref="string"/> to create the <see cref="U8String"/> from.</param>
71
    /// <remarks>
72
    /// The <see cref="U8String"/> will be created by encoding the <see cref="string"/> as UTF-8.
73
    /// </remarks>
74
    public U8String(string? value)
75
    {
76
        if (!string.IsNullOrEmpty(value))
×
77
        {
78
            this = Parse(value.AsSpan(), null);
×
79
        }
80
    }
×
81

82
    /// <summary>
83
    /// Direct constructor of <see cref="U8String"/> from a <see cref="byte"/> array.
84
    /// </summary>
85
    /// <remarks>
86
    /// Contract:
87
    /// The constructor will *always* drop the reference if the length is 0.
88
    /// Consequently, the value *must* remain null if the length is 0.
89
    /// </remarks>
90
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
91
    internal U8String(byte[]? value, int offset, int length)
92
    {
93
        if (length > 0) _value = value;
×
94
        _inner = new U8Range(offset, length);
×
95

96
        Debug.Assert(Offset >= 0);
97
        Debug.Assert(_value is null ? Length is 0 : (uint)Length > 0);
98
    }
×
99

100
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
101
    internal U8String(byte[]? value, U8Range inner)
102
    {
103
        if (inner.Length > 0) _value = value;
×
104
        _inner = inner;
×
105

106
        Debug.Assert(Offset >= 0);
107
        Debug.Assert(_value is null ? Length is 0 : (uint)Length > 0);
108
    }
×
109

110
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
111
    internal U8String(ReadOnlySpan<byte> value, bool skipValidation)
112
    {
113
        Debug.Assert(skipValidation);
114

115
        if (value.Length > 0) _value = value.ToArray();
×
116
        _inner = new U8Range(0, value.Length);
×
117

118
        Debug.Assert(Offset >= 0);
119
        Debug.Assert(_value is null ? Length is 0 : (uint)Length > 0);
120
    }
×
121

122
    /// <inheritdoc cref="U8String(ReadOnlySpan{byte})"/>
123
    // Tracks https://github.com/dotnet/runtime/issues/87569
124
    public static U8String Create(/*params*/ ReadOnlySpan<byte> value) => new(value);
×
125

126
    /// <inheritdoc cref="U8String(ImmutableArray{byte})"/>
127
    public static U8String Create(ImmutableArray<byte> value) => new(value);
×
128

129
    /// <inheritdoc cref="U8String(string)"/>
130
    public static U8String Create(string value) => new(value);
×
131

132
    /// <inheritdoc cref="U8String(ReadOnlySpan{char})"/>
133
    public static U8String Create(/*params*/ ReadOnlySpan<char> value) => new(value);
×
134

135
    /// <inheritdoc cref="U8StringExtensions.ToU8String{T}(T)"/>
136
    public static U8String Create<T>(T value)
137
        where T : IUtf8SpanFormattable
138
    {
139
        // TODO: Invert where the implementation lives?
140
        return value.ToU8String();
×
141
    }
142

143
    /// <inheritdoc cref="U8StringExtensions.ToU8String{T}(T, ReadOnlySpan{char})"/>
144
    public static U8String Create<T>(T value, ReadOnlySpan<char> format)
145
        where T : IUtf8SpanFormattable
146
    {
147
        return value.ToU8String(format);
×
148
    }
149

150
    /// <inheritdoc cref="U8StringExtensions.ToU8String{T}(T, IFormatProvider?)"/>
151
    public static U8String Create<T>(T value, IFormatProvider? provider)
152
        where T : IUtf8SpanFormattable
153
    {
154
        return value.ToU8String(provider);
×
155
    }
156

157
    /// <inheritdoc cref="U8StringExtensions.ToU8String{T}(T, ReadOnlySpan{char}, IFormatProvider?)"/>
158
    public static U8String Create<T>(T value, ReadOnlySpan<char> format, IFormatProvider? provider)
159
        where T : IUtf8SpanFormattable
160
    {
161
        return value.ToU8String(format, provider);
×
162
    }
163

164
    /// <summary>
165
    /// Creates a new <see cref="U8String"/> from <paramref name="value"/> without verifying
166
    /// if it is a valid UTF-8 sequence.
167
    /// </summary>
168
    /// <param name="value">The UTF-8 bytes to create the <see cref="U8String"/> from.</param>
169
    /// <remarks>
170
    /// The <see cref="U8String"/> will be created by copying the <paramref name="value"/> bytes if the length is greater than 0.
171
    /// </remarks>
172
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
173
    public static U8String CreateUnchecked(ReadOnlySpan<byte> value)
174
    {
175
        return new(value, skipValidation: true);
×
176
    }
177

178
    /// <summary>
179
    /// Creates a new <see cref="U8String"/> from <paramref name="value"/> without verifying
180
    /// if it is a valid UTF-8 sequence.
181
    /// </summary>
182
    /// <param name="value">The UTF-8 bytes to create the <see cref="U8String"/> from.</param>
183
    /// <remarks>
184
    /// <para>
185
    /// The <see cref="U8String"/> will be created by taking the underlying reference from the
186
    /// <paramref name="value"/> without copying if the length is greater than 0.
187
    /// </para>
188
    /// <para>
189
    /// This is a safe variant of <see cref="U8Marshal.Create(byte[])"/> which does not allocate.
190
    /// </para>
191
    /// </remarks>
192
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
193
    public static U8String CreateUnchecked(ImmutableArray<byte> value)
194
    {
195
        var bytes = ImmutableCollectionsMarshal.AsArray(value);
×
196
        if (bytes != null)
×
197
        {
198
            return new(bytes, 0, bytes.Length);
×
199
        }
200

201
        return default;
×
202
    }
203

204
    // TODO: Offset-taking overloads?
205
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
206
    public static U8String Read(Stream stream)
207
    {
208
        return stream.ReadToU8String();
×
209
    }
210

211
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
212
    public static U8String Read(SafeFileHandle handle)
213
    {
214
        return handle.ReadToU8String();
×
215
    }
216

217
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
218
    public static Task<U8String> Read(FileStream stream, CancellationToken ct = default)
219
    {
220
        return stream.ReadToU8StringAsync(ct);
×
221
    }
222

223
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
224
    public static Task<U8String> Read(SafeFileHandle handle, CancellationToken ct = default)
225
    {
226
        return handle.ReadToU8StringAsync(ct: ct);
×
227
    }
228

229
    public static U8String Move([MaybeNull] ref byte[]? value)
230
    {
231
        var source = value;
×
232
        value = null;
×
233
        var result = default(U8String);
×
234

235
        if (source?.Length > 0)
×
236
        {
237
            Validate(source);
×
238
            result = new U8String(source, 0, source.Length);
×
239
        }
240

241
        return result;
×
242
    }
243

244
    public static U8String Move([MaybeNull] ref byte[]? value, int offset, int length)
245
    {
246
        var source = value;
×
247
        value = null;
×
248
        var result = default(U8String);
×
249

250
        if (source != null)
×
251
        {
252
            Validate(source.AsSpan().Slice(offset, length));
×
253
            result = new U8String(source, offset, length);
×
254
        }
255

256
        return result;
×
257
    }
258

259
    /// <summary>
260
    /// Clones the <see cref="U8String"/> by copying the underlying
261
    /// <see cref="Length"/> of bytes into a new <see cref="U8String"/> instance.
262
    /// </summary>
263
    /// <remarks>
264
    /// <para>
265
    /// This method is useful when a particular <see cref="U8String"/> is a slice of a larger
266
    /// <see cref="U8String"/> that is no longer needed and can be garbage collected.
267
    /// This allows the GC to collect the larger <see cref="U8String"/> and reclaim the memory
268
    /// it would hold otherwise.
269
    /// </para>
270
    /// <para>
271
    /// Example:
272
    /// <code>
273
    /// var articleText = await httpClient.GetU8StringAsync("https://example.com/article.txt");
274
    /// var previewText = articleText[..100].Clone();
275
    /// </code>
276
    /// </para>
277
    /// </remarks>
278
    public U8String Clone() => new(this, skipValidation: true);
×
279

280
    /// <inheritdoc />
281
    object ICloneable.Clone() => Clone();
×
282
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc