Skip to content

Commit b8a9b50

Browse files
Obsolete ConfigIterator and add standard enumerators to Config. (#426)
* Add standard enumerators to `Config`. * Update tests. * Obsolete `ConfigIterator`.
1 parent b80cbaa commit b8a9b50

File tree

5 files changed

+129
-44
lines changed

5 files changed

+129
-44
lines changed

docs/obsoletions.md

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ Following [the deprecation policy of TileDB Embedded][core-deprecation], obsolet
88
|----------------|---------------------|------------------|
99
|[`TILEDB0001`](#TILEDB0001)[`TILEDB0011`](#TILEDB0011)|5.3.0|5.5.0|
1010
|[`TILEDB0012`](#TILEDB0012)[`TILEDB0013`](#TILEDB0013)|5.7.0|5.9.0|
11-
|[`TILEDB0012`](#TILEDB0014)[`TILEDB0013`](#TILEDB0014)|5.8.0|5.10.0|
11+
|[`TILEDB0014`](#TILEDB0014)[`TILEDB0014`](#TILEDB0014)|5.8.0|5.10.0|
12+
|[`TILEDB0015`](#TILEDB0015)[`TILEDB0015`](#TILEDB0015)|5.13.0|5.15.0|
1213

1314
## `TILEDB0001` - Enum value names that start with `TILEDB_` were replaced with C#-friendly names.
1415

@@ -348,4 +349,18 @@ Some APIs in the `TileDB.Interop` namespace that were inadvertently removed in v
348349

349350
Stop using the obsoleted APIs. No other public API of `TileDB.CSharp` depends on them.
350351

352+
## `TILEDB0015` - `ConfigIterator` is obsolete.
353+
354+
<a name="TILEDB0015"></a>
355+
356+
The `ConfigIterator` class is unintuitive to use. In version 5.13.0 it was marked as obsolete and replaced by `Config` implementing `IEnumerable<KeyValuePair<string,string>>`.
357+
358+
### Version introduced
359+
360+
5.13.0
361+
362+
### Recommended action
363+
364+
Replace uses of `ConfigIterator` with enumerating the `Config` object directly using a `foreach` loop or LINQ. To get only the config options that start with a specific prefix, call the `Config.EnumerateOptions` method and enumerate its returned object.
365+
351366
[core-deprecation]: https://github.com/TileDB-Inc/TileDB/blob/dev/doc/policy/api_changes.md

sources/TileDB.CSharp/Config.cs

Lines changed: 64 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System;
2-
using System.Text;
2+
using System.Collections;
3+
using System.Collections.Generic;
34
using TileDB.CSharp.Marshalling.SafeHandles;
45
using TileDB.Interop;
56
using ConfigHandle = TileDB.CSharp.Marshalling.SafeHandles.ConfigHandle;
@@ -9,7 +10,7 @@ namespace TileDB.CSharp;
910
/// <summary>
1011
/// Represents a TileDB config object.
1112
/// </summary>
12-
public sealed unsafe class Config : IDisposable
13+
public sealed unsafe class Config : IDisposable, IEnumerable<KeyValuePair<string, string>>
1314
{
1415
private readonly ConfigHandle _handle;
1516

@@ -61,6 +62,23 @@ public void Set(string param, string value)
6162
ErrorHandling.CheckLastError(&p_tiledb_error, status);
6263
}
6364

65+
/// <summary>
66+
/// Enumerates the config's options.
67+
/// </summary>
68+
public IEnumerator<KeyValuePair<string, string>> GetEnumerator() => new Enumerator(this, "");
69+
70+
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
71+
72+
/// <summary>
73+
/// Enumerates the config's options that start with a specific prefix.
74+
/// </summary>
75+
/// <param name="prefix">The prefix of the options to enumerate.</param>
76+
public IEnumerable<KeyValuePair<string, string>> EnumerateOptions(string prefix)
77+
{
78+
ErrorHandling.ThrowIfNull(prefix);
79+
return new PrefixEnumerable(this, prefix);
80+
}
81+
6482
/// <summary>
6583
/// Gets the value of a parameter.
6684
/// </summary>
@@ -177,4 +195,48 @@ public bool Cmp(ref Config other)
177195
Methods.tiledb_config_compare(handle, otherHandle, &equal);
178196
return equal == 1;
179197
}
198+
199+
private sealed class PrefixEnumerable(Config config, string prefix) : IEnumerable<KeyValuePair<string, string>>
200+
{
201+
public IEnumerator<KeyValuePair<string, string>> GetEnumerator() =>
202+
new Enumerator(config, prefix);
203+
204+
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
205+
}
206+
207+
private sealed class Enumerator(Config config, string prefix) : IEnumerator<KeyValuePair<string, string>>
208+
{
209+
#pragma warning disable TILEDB0015 // Type or member is obsolete
210+
// We use ConfigIterator as an implementation detail.
211+
// In the future, ConfigIterator will become internal and replace this class.
212+
private readonly ConfigIterator _iterator = new(config.Handle, prefix);
213+
#pragma warning restore TILEDB0015 // Type or member is obsolete
214+
215+
private readonly string _prefix = prefix;
216+
217+
private KeyValuePair<string, string>? _current;
218+
219+
public void Dispose() => _iterator.Dispose();
220+
221+
public bool MoveNext()
222+
{
223+
if (!_iterator.Done())
224+
{
225+
return false;
226+
}
227+
_current = _iterator.HereImpl();
228+
_iterator.Next();
229+
return true;
230+
}
231+
232+
public KeyValuePair<string, string> Current => _current!.Value; // Will throw if MoveNext has not been called before.
233+
234+
object IEnumerator.Current => Current;
235+
236+
public void Reset()
237+
{
238+
_iterator.Reset(_prefix);
239+
_current = null;
240+
}
241+
}
180242
}

sources/TileDB.CSharp/ConfigIterator.cs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
using System;
2+
using System.Collections.Generic;
23
using TileDB.CSharp.Marshalling.SafeHandles;
34
using TileDB.Interop;
45
using ConfigHandle = TileDB.CSharp.Marshalling.SafeHandles.ConfigHandle;
56
using ConfigIteratorHandle = TileDB.CSharp.Marshalling.SafeHandles.ConfigIteratorHandle;
67

78
namespace TileDB.CSharp;
89

10+
[Obsolete(Obsoletions.ConfigIteratorMessage, DiagnosticId = Obsoletions.ConfigIteratorDiagId, UrlFormat = Obsoletions.SharedUrlFormat)]
911
public sealed unsafe class ConfigIterator : IDisposable
1012
{
1113
private readonly ConfigIteratorHandle _handle;
@@ -36,7 +38,8 @@ private void Dispose(bool disposing)
3638

3739
internal ConfigIteratorHandle Handle => _handle;
3840

39-
public Tuple<string, string> Here()
41+
// Internal overload that returns KVP to avoid the Tuple allocation.
42+
internal KeyValuePair<string, string> HereImpl()
4043
{
4144
tiledb_error_t* p_tiledb_error;
4245
sbyte* paramPtr;
@@ -51,7 +54,13 @@ public Tuple<string, string> Here()
5154

5255
string param = MarshaledStringOut.GetStringFromNullTerminated(paramPtr);
5356
string value = MarshaledStringOut.GetStringFromNullTerminated(valuePtr);
54-
return new Tuple<string, string>(param, value);
57+
return new KeyValuePair<string, string>(param, value);
58+
}
59+
60+
public Tuple<string, string> Here()
61+
{
62+
var here = HereImpl();
63+
return new Tuple<string, string>(here.Key, here.Value);
5564
}
5665

5766
public void Next()

sources/TileDB.CSharp/Obsoletions.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,4 +47,7 @@ internal static class Obsoletions
4747

4848
public const string TileDBInterop3Message = "Members of the TileDB.Interop namespace should not be used by user code and will become internal in a future version.";
4949
public const string TileDBInterop3DiagId = "TILEDB0014";
50+
51+
public const string ConfigIteratorMessage = "ConfigIterator is obsolete. Directly enumerate a Config or call its EnumerateOptions method instead.";
52+
public const string ConfigIteratorDiagId = "TILEDB0015";
5053
}

tests/TileDB.CSharp.Test/ConfigTest.cs

Lines changed: 35 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -89,112 +89,108 @@ public void ConfigIterator()
8989
// Iterate the configuration
9090
var iter = config.Iterate("vfs.s3.");
9191

92-
while (!iter.Done())
92+
foreach (var config_entry_pair in config.EnumerateOptions("vfs.s3."))
9393
{
94-
95-
// Get current param, value from iterator
96-
var config_entry_pair = iter.Here();
97-
98-
switch (config_entry_pair.Item1)
94+
switch (config_entry_pair.Key)
9995
{
10096
case "aws_access_key_id":
101-
Assert.AreEqual("", config_entry_pair.Item2);
97+
Assert.AreEqual("", config_entry_pair.Value);
10298
break;
10399
case "aws_external_id":
104-
Assert.AreEqual("", config_entry_pair.Item2);
100+
Assert.AreEqual("", config_entry_pair.Value);
105101
break;
106102
case "aws_load_frequency":
107-
Assert.AreEqual("", config_entry_pair.Item2);
103+
Assert.AreEqual("", config_entry_pair.Value);
108104
break;
109105
case "aws_role_arn":
110-
Assert.AreEqual("", config_entry_pair.Item2);
106+
Assert.AreEqual("", config_entry_pair.Value);
111107
break;
112108
case "aws_secret_access_key":
113-
Assert.AreEqual("", config_entry_pair.Item2);
109+
Assert.AreEqual("", config_entry_pair.Value);
114110
break;
115111
case "aws_session_name":
116-
Assert.AreEqual("", config_entry_pair.Item2);
112+
Assert.AreEqual("", config_entry_pair.Value);
117113
break;
118114
case "aws_session_token":
119-
Assert.AreEqual("", config_entry_pair.Item2);
115+
Assert.AreEqual("", config_entry_pair.Value);
120116
break;
121117
case "bucket_canned_acl":
122-
Assert.AreEqual("NOT_SET", config_entry_pair.Item2);
118+
Assert.AreEqual("NOT_SET", config_entry_pair.Value);
123119
break;
124120
case "ca_file":
125-
Assert.AreEqual("", config_entry_pair.Item2);
121+
Assert.AreEqual("", config_entry_pair.Value);
126122
break;
127123
case "ca_path":
128-
Assert.AreEqual("", config_entry_pair.Item2);
124+
Assert.AreEqual("", config_entry_pair.Value);
129125
break;
130126
case "connect_max_tries":
131-
Assert.AreEqual("5", config_entry_pair.Item2);
127+
Assert.AreEqual("5", config_entry_pair.Value);
132128
break;
133129
case "connect_scale_factor":
134-
Assert.AreEqual("25", config_entry_pair.Item2);
130+
Assert.AreEqual("25", config_entry_pair.Value);
135131
break;
136132
case "connect_timeout_ms":
137-
Assert.AreEqual("10800", config_entry_pair.Item2);
133+
Assert.AreEqual("10800", config_entry_pair.Value);
138134
break;
139135
case "endpoint_override":
140-
Assert.AreEqual("", config_entry_pair.Item2);
136+
Assert.AreEqual("", config_entry_pair.Value);
141137
break;
142138
case "logging_level":
143-
Assert.AreEqual("Off", config_entry_pair.Item2);
139+
Assert.AreEqual("Off", config_entry_pair.Value);
144140
break;
145141
case "max_parallel_ops":
146-
Assert.AreEqual(Environment.ProcessorCount.ToString(), config_entry_pair.Item2);
142+
Assert.AreEqual(Environment.ProcessorCount.ToString(), config_entry_pair.Value);
147143
break;
148144
case "multipart_part_size":
149-
Assert.AreEqual("5242880", config_entry_pair.Item2);
145+
Assert.AreEqual("5242880", config_entry_pair.Value);
150146
break;
151147
case "object_canned_acl":
152-
Assert.AreEqual("NOT_SET", config_entry_pair.Item2);
148+
Assert.AreEqual("NOT_SET", config_entry_pair.Value);
153149
break;
154150
case "proxy_host":
155-
Assert.AreEqual("", config_entry_pair.Item2);
151+
Assert.AreEqual("", config_entry_pair.Value);
156152
break;
157153
case "proxy_password":
158-
Assert.AreEqual("", config_entry_pair.Item2);
154+
Assert.AreEqual("", config_entry_pair.Value);
159155
break;
160156
case "proxy_port":
161-
Assert.AreEqual("0", config_entry_pair.Item2);
157+
Assert.AreEqual("0", config_entry_pair.Value);
162158
break;
163159
case "proxy_scheme":
164-
Assert.AreEqual("http", config_entry_pair.Item2);
160+
Assert.AreEqual("http", config_entry_pair.Value);
165161
break;
166162
case "proxy_username":
167-
Assert.AreEqual("", config_entry_pair.Item2);
163+
Assert.AreEqual("", config_entry_pair.Value);
168164
break;
169165
case "region":
170-
Assert.AreEqual("us-east-1", config_entry_pair.Item2);
166+
Assert.AreEqual("us-east-1", config_entry_pair.Value);
171167
break;
172168
case "request_timeout_ms":
173-
Assert.AreEqual("3000", config_entry_pair.Item2);
169+
Assert.AreEqual("3000", config_entry_pair.Value);
174170
break;
175171
case "requester_pays":
176-
Assert.AreEqual("false", config_entry_pair.Item2);
172+
Assert.AreEqual("false", config_entry_pair.Value);
177173
break;
178174
case "scheme":
179-
Assert.AreEqual("https", config_entry_pair.Item2);
175+
Assert.AreEqual("https", config_entry_pair.Value);
180176
break;
181177
case "skip_init":
182-
Assert.AreEqual("false", config_entry_pair.Item2);
178+
Assert.AreEqual("false", config_entry_pair.Value);
183179
break;
184180
case "sse":
185-
Assert.AreEqual("", config_entry_pair.Item2);
181+
Assert.AreEqual("", config_entry_pair.Value);
186182
break;
187183
case "sse_kms_key_id":
188-
Assert.AreEqual("", config_entry_pair.Item2);
184+
Assert.AreEqual("", config_entry_pair.Value);
189185
break;
190186
case "use_multipart_upload":
191-
Assert.AreEqual("true", config_entry_pair.Item2);
187+
Assert.AreEqual("true", config_entry_pair.Value);
192188
break;
193189
case "use_virtual_addressing":
194-
Assert.AreEqual("true", config_entry_pair.Item2);
190+
Assert.AreEqual("true", config_entry_pair.Value);
195191
break;
196192
case "verify_ssl":
197-
Assert.AreEqual("true", config_entry_pair.Item2);
193+
Assert.AreEqual("true", config_entry_pair.Value);
198194
break;
199195
}
200196
iter.Next();

0 commit comments

Comments
 (0)