Skip to content

Commit 4117107

Browse files
authored
Add (experimental) native AOT support (#8530)
1 parent 5159239 commit 4117107

35 files changed

+628
-722
lines changed

src/Elastic.Clients.Elasticsearch/Elastic.Clients.Elasticsearch.csproj

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
<Project Sdk="Microsoft.NET.Sdk">
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
23
<PropertyGroup>
34
<PackageId>Elastic.Clients.Elasticsearch</PackageId>
45
<Title>Elastic.Clients.Elasticsearch - Official Elasticsearch .NET Client</Title>
@@ -9,6 +10,7 @@
910
<ProduceReferenceAssembly>true</ProduceReferenceAssembly>
1011
<PackageReadmeFile>README.md</PackageReadmeFile>
1112
</PropertyGroup>
13+
1214
<PropertyGroup>
1315
<IsPackable>true</IsPackable>
1416
<GenerateDocumentationFile>true</GenerateDocumentationFile>
@@ -18,24 +20,38 @@
1820
<Nullable>annotations</Nullable>
1921
<PolySharpIncludeRuntimeSupportedAttributes>true</PolySharpIncludeRuntimeSupportedAttributes>
2022
</PropertyGroup>
23+
24+
<PropertyGroup Condition="$([MSBuild]::IsTargetFrameworkCompatible('$(TargetFramework)', 'net8.0')) or
25+
$([MSBuild]::IsTargetFrameworkCompatible('$(TargetFramework)', 'net9.0'))">
26+
<IsAotCompatible>true</IsAotCompatible>
27+
</PropertyGroup>
28+
29+
<PropertyGroup>
30+
<JsonSerializerIsReflectionEnabledByDefault>false</JsonSerializerIsReflectionEnabledByDefault>
31+
</PropertyGroup>
32+
2133
<ItemGroup>
22-
<PackageReference Include="Elastic.Transport" Version="0.5.9" />
34+
<PackageReference Include="Elastic.Transport" Version="0.8.0" />
2335
<PackageReference Include="PolySharp" Version="1.15.0">
2436
<PrivateAssets>all</PrivateAssets>
2537
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
2638
</PackageReference>
2739
</ItemGroup>
40+
2841
<ItemGroup>
2942
<InternalsVisibleTo Include="Tests" Key="$(ExposedPublicKey)" />
3043
<InternalsVisibleTo Include="Tests.Domain" Key="$(ExposedPublicKey)" />
3144
<InternalsVisibleTo Include="Benchmarks" Key="$(ExposedPublicKey)" />
3245
</ItemGroup>
46+
3347
<ItemGroup>
3448
<AssemblyAttribute Include="CLSCompliantAttribute">
3549
<_Parameter1>true</_Parameter1>
3650
</AssemblyAttribute>
3751
</ItemGroup>
52+
3853
<ItemGroup>
3954
<None Include="..\..\README.md" Pack="true" PackagePath="\" />
4055
</ItemGroup>
56+
4157
</Project>

src/Elastic.Clients.Elasticsearch/_Shared/Api/SearchRequest.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,11 @@ protected override (string ResolvedUrl, string UrlTemplate, Dictionary<string, s
3636
[JsonConverter(typeof(SearchRequestOfTConverterFactory))]
3737
public partial class SearchRequest<TInferDocument> : SearchRequest
3838
{
39+
static SearchRequest()
40+
{
41+
DynamicallyAccessed.PublicConstructors(typeof(SearchRequestOfTConverter<TInferDocument>));
42+
}
43+
3944
public SearchRequest(Indices? indices) : base(indices)
4045
{
4146
}
@@ -67,7 +72,9 @@ public override bool CanConvert(Type typeToConvert) =>
6772
{
6873
var args = typeToConvert.GetGenericArguments();
6974

75+
#pragma warning disable IL3050
7076
return (JsonConverter)Activator.CreateInstance(typeof(SearchRequestOfTConverter<>).MakeGenericType(args[0]));
77+
#pragma warning restore IL3050
7178
}
7279
}
7380

src/Elastic.Clients.Elasticsearch/_Shared/Client/ElasticsearchClient.Esql.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,10 @@ private static IEnumerable<T> EsqlToObject<T>(ElasticsearchClient client, EsqlQu
7171
{
7272
// TODO: Improve performance
7373

74+
// TODO: fixme
75+
#pragma warning disable IL2026, IL3050
7476
using var doc = JsonSerializer.Deserialize<JsonDocument>(response.Data) ?? throw new JsonException();
77+
#pragma warning restore IL2026, IL3050
7578

7679
if (!doc.RootElement.TryGetProperty("columns"u8, out var columns) || (columns.ValueKind is not JsonValueKind.Array))
7780
throw new JsonException("");

src/Elastic.Clients.Elasticsearch/_Shared/Core/DateTime/DateMath/DateMath.cs

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -45,10 +45,10 @@ internal DateMath(Union<DateTime, string> anchor, DateMathTime range, DateMathOp
4545

4646
public static implicit operator DateMath(string dateMath) => FromString(dateMath);
4747

48-
public static DateMath FromString(string dateMath)
48+
public static DateMath FromString(string? dateMath)
4949
{
50-
if (dateMath == null)
51-
return null;
50+
if (dateMath is null)
51+
throw new ArgumentNullException(nameof(dateMath));
5252

5353
var match = DateMathRegex.Match(dateMath);
5454
if (!match.Success)
@@ -61,9 +61,12 @@ public static DateMath FromString(string dateMath)
6161
var rangeString = match.Groups["ranges"].Value;
6262
do
6363
{
64-
var nextRangeStart = rangeString.Substring(1).IndexOfAny(new[] { '+', '-', '/' });
64+
var nextRangeStart = rangeString[1..].IndexOfAny(['+', '-', '/']);
6565
if (nextRangeStart == -1)
66+
{
6667
nextRangeStart = rangeString.Length - 1;
68+
}
69+
6770
var unit = rangeString.Substring(1, nextRangeStart);
6871
if (rangeString.StartsWith("+", StringComparison.Ordinal))
6972
{
@@ -73,19 +76,25 @@ public static DateMath FromString(string dateMath)
7376
else if (rangeString.StartsWith("-", StringComparison.Ordinal))
7477
{
7578
math = math.Subtract(unit);
76-
rangeString = rangeString.Substring(nextRangeStart + 1);
79+
rangeString = rangeString[(nextRangeStart + 1)..];
7780
}
7881
else
79-
rangeString = null;
82+
{
83+
break;
84+
}
8085
} while (!rangeString.IsNullOrEmpty());
8186
}
8287

83-
if (match.Groups["rounding"].Success)
88+
if (!match.Groups["rounding"].Success)
8489
{
85-
var rounding = match.Groups["rounding"].Value.Substring(1).ToEnum<DateMathTimeUnit>(StringComparison.Ordinal);
86-
if (rounding.HasValue)
87-
return math.RoundTo(rounding.Value);
90+
return math;
8891
}
92+
93+
if (EnumValue<DateMathTimeUnit>.TryParse(match.Groups["rounding"].Value[1..], out var rounding))
94+
{
95+
return math.RoundTo(rounding);
96+
}
97+
8998
return math;
9099
}
91100

src/Elastic.Clients.Elasticsearch/_Shared/Core/DateTime/DateMath/DateMathTime.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,8 +79,9 @@ public DateMathTime(string timeUnit, MidpointRounding rounding = MidpointRoundin
7979
{
8080
"M" => DateMathTimeUnit.Month,
8181
"m" => DateMathTimeUnit.Minute,
82-
_ => intervalValue.ToEnum<DateMathTimeUnit>().GetValueOrDefault(),
82+
_ => EnumValue<DateMathTimeUnit>.TryParse(intervalValue, out var result) ? result : default
8383
};
84+
8485
SetWholeFactorIntervalAndSeconds(fraction, interval, rounding);
8586
}
8687

src/Elastic.Clients.Elasticsearch/_Shared/Core/EnumValueParser.cs renamed to src/Elastic.Clients.Elasticsearch/_Shared/Core/EnumValue.cs

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,12 @@
22
// Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
33
// See the LICENSE file in the project root for more information.
44

5+
using System.Diagnostics.CodeAnalysis;
6+
57
#if !NET5_0_OR_GREATER
8+
69
using System.Linq;
10+
711
#endif
812

913
namespace Elastic.Clients.Elasticsearch;
@@ -12,12 +16,13 @@ namespace Elastic.Clients.Elasticsearch;
1216
using System.Collections.Generic;
1317
using System.Runtime.Serialization;
1418

15-
internal static class EnumValueParser<T>
19+
internal static class EnumValue<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields)] T>
1620
where T : struct, Enum
1721
{
1822
private static readonly Dictionary<string, T> ValueMap = new(StringComparer.OrdinalIgnoreCase);
23+
private static readonly Dictionary<T, string> NameMap = new();
1924

20-
static EnumValueParser()
25+
static EnumValue()
2126
{
2227
#if NET5_0_OR_GREATER
2328
foreach (var value in Enum.GetValues<T>())
@@ -27,12 +32,14 @@ static EnumValueParser()
2732
{
2833
var name = value.ToString();
2934
ValueMap[name] = value;
35+
NameMap[value] = name;
3036

3137
var field = typeof(T).GetField(name);
3238
var attribute = (EnumMemberAttribute?)Attribute.GetCustomAttribute(field!, typeof(EnumMemberAttribute));
3339
if (attribute?.Value is not null)
3440
{
3541
ValueMap[attribute.Value] = value;
42+
NameMap[value] = attribute.Value;
3643
}
3744
}
3845
}
@@ -51,4 +58,19 @@ public static T Parse(string input)
5158

5259
throw new ArgumentException($"Unknown member '{input}' for enum '{typeof(T).Name}'.");
5360
}
61+
62+
public static bool TryGetString(T value, [NotNullWhen(true)] out string? result)
63+
{
64+
return NameMap.TryGetValue(value, out result);
65+
}
66+
67+
public static string GetString(T value)
68+
{
69+
if (NameMap.TryGetValue(value, out var result))
70+
{
71+
return result;
72+
}
73+
74+
throw new ArgumentException($"Unknown member '{value}' for enum '{typeof(T).Name}'.");
75+
}
5476
}

src/Elastic.Clients.Elasticsearch/_Shared/Core/Extensions/Extensions.cs

Lines changed: 1 addition & 118 deletions
Original file line numberDiff line numberDiff line change
@@ -3,115 +3,17 @@
33
// See the LICENSE file in the project root for more information.
44

55
using System;
6-
using System.Collections.Concurrent;
76
using System.Collections.Generic;
87
using System.Diagnostics.CodeAnalysis;
98
using System.Linq;
10-
using System.Reflection;
119
using System.Runtime.ExceptionServices;
12-
using System.Runtime.Serialization;
13-
using System.Text;
1410
using System.Threading;
1511
using System.Threading.Tasks;
1612

1713
namespace Elastic.Clients.Elasticsearch;
1814

1915
internal static class Extensions
2016
{
21-
private static readonly ConcurrentDictionary<string, object> EnumCache = new();
22-
23-
//internal static bool NotWritable(this Query q) => q == null || !q.IsWritable;
24-
25-
//internal static bool NotWritable(this IEnumerable<Query> qs) => qs == null || qs.All(q => q.NotWritable());
26-
27-
internal static string ToEnumValue<T>(this T enumValue) where T : struct
28-
{
29-
var enumType = typeof(T);
30-
var name = Enum.GetName(enumType, enumValue);
31-
var enumMemberAttribute = enumType.GetField(name).GetCustomAttribute<EnumMemberAttribute>();
32-
33-
//if (enumMemberAttribute != null)
34-
//return enumMemberAttribute.Value;
35-
36-
//var alternativeEnumMemberAttribute = enumType.GetField(name).GetCustomAttribute<AlternativeEnumMemberAttribute>();
37-
38-
return enumMemberAttribute != null
39-
? enumMemberAttribute.Value
40-
: enumValue.ToString();
41-
}
42-
43-
internal static T? ToEnum<T>(this string str, StringComparison comparison = StringComparison.OrdinalIgnoreCase) where T : struct
44-
{
45-
if (str == null)
46-
return null;
47-
48-
var enumType = typeof(T);
49-
var key = $"{enumType.Name}.{str}";
50-
if (EnumCache.TryGetValue(key, out var value))
51-
return (T)value;
52-
53-
foreach (var name in Enum.GetNames(enumType))
54-
{
55-
if (name.Equals(str, comparison))
56-
{
57-
var v = (T)Enum.Parse(enumType, name, true);
58-
EnumCache.TryAdd(key, v);
59-
return v;
60-
}
61-
62-
var enumFieldInfo = enumType.GetField(name);
63-
var enumMemberAttribute = enumFieldInfo.GetCustomAttribute<EnumMemberAttribute>();
64-
if (enumMemberAttribute?.Value.Equals(str, comparison) ?? false)
65-
{
66-
var v = (T)Enum.Parse(enumType, name);
67-
EnumCache.TryAdd(key, v);
68-
return v;
69-
}
70-
71-
//var alternativeEnumMemberAttribute = enumFieldInfo.GetCustomAttribute<AlternativeEnumMemberAttribute>();
72-
//if (alternativeEnumMemberAttribute?.Value.Equals(str, comparison) ?? false)
73-
//{
74-
// var v = (T)Enum.Parse(enumType, name);
75-
// EnumCache.TryAdd(key, v);
76-
// return v;
77-
//}
78-
}
79-
80-
return null;
81-
}
82-
83-
internal static TReturn InvokeOrDefault<T, TReturn>(this Func<T, TReturn> func, T @default)
84-
where T : class, TReturn where TReturn : class =>
85-
func?.Invoke(@default) ?? @default;
86-
87-
internal static TReturn InvokeOrDefault<T1, T2, TReturn>(this Func<T1, T2, TReturn> func, T1 @default,
88-
T2 param2)
89-
where T1 : class, TReturn where TReturn : class =>
90-
func?.Invoke(@default, param2) ?? @default;
91-
92-
internal static IEnumerable<T> DistinctBy<T, TKey>(this IEnumerable<T> items, Func<T, TKey> property) =>
93-
items.GroupBy(property).Select(x => x.First());
94-
95-
internal static string Utf8String(this byte[] bytes) =>
96-
bytes == null ? null : Encoding.UTF8.GetString(bytes, 0, bytes.Length);
97-
98-
internal static byte[] Utf8Bytes(this string s) => s.IsNullOrEmpty() ? null : Encoding.UTF8.GetBytes(s);
99-
100-
internal static bool IsNullOrEmpty(this IndexName value) => value == null || value.GetHashCode() == 0;
101-
102-
internal static bool IsNullable(this Type type) =>
103-
type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>);
104-
105-
internal static void ThrowIfNullOrEmpty(this string @object, string parameterName, string when = null)
106-
{
107-
@object.ThrowIfNull(parameterName, when);
108-
if (string.IsNullOrWhiteSpace(@object))
109-
{
110-
throw new ArgumentException(
111-
"Argument can't be null or empty" + (when.IsNullOrEmpty() ? "" : " when " + when), parameterName);
112-
}
113-
}
114-
11517
// ReSharper disable once ParameterOnlyUsedForPreconditionCheck.Global
11618
internal static void ThrowIfEmpty<T>(this IEnumerable<T> @object, string parameterName)
11719
{
@@ -164,9 +66,6 @@ internal static IEnumerable<T> AddIfNotNull<T>(this IEnumerable<T> list, T other
16466
return l;
16567
}
16668

167-
internal static bool HasAny<T>(this IEnumerable<T> list, Func<T, bool> predicate) =>
168-
list != null && list.Any(predicate);
169-
17069
internal static bool HasAny<T>(this IEnumerable<T> list) => list != null && list.Any();
17170

17271
internal static bool IsNullOrEmpty<T>(this IEnumerable<T>? list)
@@ -195,7 +94,7 @@ internal static bool IsNullOrEmptyCommaSeparatedList(this string? value, [NotNul
19594
if (string.IsNullOrWhiteSpace(value))
19695
return true;
19796

198-
split = value.Split(new[] {','}, StringSplitOptions.RemoveEmptyEntries)
97+
split = value.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
19998
.Where(t => !t.IsNullOrEmpty())
20099
.Select(t => t.Trim())
201100
.ToArray();
@@ -224,12 +123,6 @@ internal static void AddRangeIfNotNull<T>(this List<T> list, IEnumerable<T> item
224123
list.AddRange(item.Where(x => x != null));
225124
}
226125

227-
internal static Dictionary<TKey, TValue> NullIfNoKeys<TKey, TValue>(this Dictionary<TKey, TValue> dictionary)
228-
{
229-
var i = dictionary?.Count;
230-
return i.GetValueOrDefault(0) > 0 ? dictionary : null;
231-
}
232-
233126
internal static async Task ForEachAsync<TSource, TResult>(
234127
this IEnumerable<TSource> lazyList,
235128
Func<TSource, long, Task<TResult>> taskSelector,
@@ -297,14 +190,4 @@ long page
297190
additionalRateLimiter?.Release();
298191
}
299192
}
300-
301-
internal static bool NullOrEquals<T>(this T o, T other)
302-
{
303-
if (o == null && other == null)
304-
return true;
305-
if (o == null || other == null)
306-
return false;
307-
308-
return o.Equals(other);
309-
}
310193
}

0 commit comments

Comments
 (0)