Skip to content

Commit

Permalink
unify the usage of lazy in ClientProvider (#5469)
Browse files Browse the repository at this point in the history
Fixes #5470
  • Loading branch information
ArcturusZhang authored Jan 3, 2025
1 parent 254aba7 commit 3f9c94d
Showing 1 changed file with 24 additions and 25 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,12 @@ private record OAuth2Fields(FieldProvider AuthField, FieldProvider Authorization

private FieldProvider? _apiVersionField;
private readonly Lazy<IReadOnlyList<ParameterProvider>> _subClientInternalConstructorParams;
private IReadOnlyList<Lazy<ClientProvider>>? _subClients;
private readonly Lazy<IReadOnlyList<ClientProvider>> _subClients;
private RestClientProvider? _restClient;
private readonly InputParameter[] _allClientParameters;
private Lazy<List<FieldProvider>> _additionalClientFields;
private readonly IReadOnlyList<InputParameter> _allClientParameters;
private Lazy<IReadOnlyList<FieldProvider>> _additionalClientFields;

private Lazy<ParameterProvider?> ClientOptionsParameter { get; }
private IReadOnlyList<Lazy<ClientProvider>> SubClients => _subClients ??= GetSubClients();

// for mocking
#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
Expand Down Expand Up @@ -141,6 +140,7 @@ public ClientProvider(InputClient inputClient)
_allClientParameters = _inputClient.Parameters.Concat(_inputClient.Operations.SelectMany(op => op.Parameters).Where(p => p.Kind == InputOperationParameterKind.Client)).DistinctBy(p => p.Name).ToArray();
_subClientInternalConstructorParams = new(GetSubClientInternalConstructorParameters);
_clientParameters = new(GetClientParameters);
_subClients = new(GetSubClients);
}

private IReadOnlyList<ParameterProvider> GetSubClientInternalConstructorParameters()
Expand Down Expand Up @@ -225,18 +225,18 @@ protected override FieldProvider[] BuildFields()
fields.AddRange(_additionalClientFields.Value);

// add sub-client caching fields
foreach (var subClient in SubClients)
foreach (var subClient in _subClients.Value)
{
if (subClient.Value.Methods.Count != 0 && subClient.Value._clientCachingField != null)
if (subClient.Methods.Count != 0 && subClient._clientCachingField != null)
{
fields.Add(subClient.Value._clientCachingField);
fields.Add(subClient._clientCachingField);
}
}

return [.. fields];
}

private List<FieldProvider> BuildAdditionalClientFields()
private IReadOnlyList<FieldProvider> BuildAdditionalClientFields()
{
var fields = new List<FieldProvider>();
// Add optional client parameters as fields
Expand Down Expand Up @@ -452,7 +452,8 @@ [.. primaryCtorOrderedParams.Select(p => p.InitializationValue ?? p)

protected override MethodProvider[] BuildMethods()
{
var subClientCount = SubClients.Count;
var subClients = _subClients.Value;
var subClientCount = subClients.Count;
List<MethodProvider> methods = new List<MethodProvider>((_inputClient.Operations.Count * 4) + subClientCount);

// Build methods for all the operations
Expand All @@ -474,19 +475,18 @@ protected override MethodProvider[] BuildMethods()
var parentClientFields = Fields.ToDictionary(f => f.Name.ToVariableName());

// Build factory accessor methods for the sub-clients
foreach (var subClient in SubClients)
foreach (var subClient in subClients)
{
var subClientInstance = subClient.Value;
if (subClientInstance._clientCachingField is null || subClientInstance.Methods.Count == 0)
if (subClient._clientCachingField is null || subClient.Methods.Count == 0)
{
continue;
}

var cachedClientFieldVar = new VariableExpression(subClientInstance.Type, subClientInstance._clientCachingField.Declaration, IsRef: true);
var cachedClientFieldVar = new VariableExpression(subClient.Type, subClient._clientCachingField.Declaration, IsRef: true);
List<ValueExpression> subClientConstructorArgs = new(3);

// Populate constructor arguments
foreach (var param in subClientInstance._subClientInternalConstructorParams.Value)
foreach (var param in subClient._subClientInternalConstructorParams.Value)
{
if (parentClientProperties.TryGetValue(param.Name, out var parentProperty))
{
Expand All @@ -501,23 +501,23 @@ protected override MethodProvider[] BuildMethods()
// Create the interlocked compare exchange expression for the body
var interlockedCompareExchange = Static(typeof(Interlocked)).Invoke(
nameof(Interlocked.CompareExchange),
[cachedClientFieldVar, New.Instance(subClientInstance.Type, subClientConstructorArgs), Null]);
var factoryMethodName = subClient.Value.Name.EndsWith(ClientSuffix, StringComparison.OrdinalIgnoreCase)
? $"Get{subClient.Value.Name}"
: $"Get{subClient.Value.Name}{ClientSuffix}";
[cachedClientFieldVar, New.Instance(subClient.Type, subClientConstructorArgs), Null]);
var factoryMethodName = subClient.Name.EndsWith(ClientSuffix, StringComparison.OrdinalIgnoreCase)
? $"Get{subClient.Name}"
: $"Get{subClient.Name}{ClientSuffix}";

var factoryMethod = new MethodProvider(
new(
factoryMethodName,
$"Initializes a new instance of {subClientInstance.Type.Name}",
$"Initializes a new instance of {subClient.Type.Name}",
MethodSignatureModifiers.Public | MethodSignatureModifiers.Virtual,
subClientInstance.Type,
subClient.Type,
null,
[]),
// return Volatile.Read(ref _cachedClient) ?? Interlocked.CompareExchange(ref _cachedClient, new Client(_pipeline, _keyCredential, _endpoint), null) ?? _cachedClient;
Return(
Static(typeof(Volatile)).Invoke(nameof(Volatile.Read), cachedClientFieldVar)
.NullCoalesce(interlockedCompareExchange.NullCoalesce(subClientInstance._clientCachingField))),
.NullCoalesce(interlockedCompareExchange.NullCoalesce(subClient._clientCachingField))),
this);
methods.Add(factoryMethod);
}
Expand Down Expand Up @@ -545,18 +545,17 @@ private ParameterProvider BuildClientEndpointParameter()
};
}

// TODO: Update method to be more efficient
private IReadOnlyList<Lazy<ClientProvider>> GetSubClients()
private IReadOnlyList<ClientProvider> GetSubClients()
{
var inputClients = ClientModelPlugin.Instance.InputLibrary.InputNamespace.Clients;
var subClients = new List<Lazy<ClientProvider>>(inputClients.Count);
var subClients = new List<ClientProvider>(inputClients.Count);

foreach (var client in inputClients)
{
// add direct child clients
if (client.Parent != null && client.Parent == _inputClient.Key)
{
subClients.Add(new(() => ClientModelPlugin.Instance.TypeFactory.CreateClient(client)));
subClients.Add(ClientModelPlugin.Instance.TypeFactory.CreateClient(client));
}
}

Expand Down

0 comments on commit 3f9c94d

Please sign in to comment.