forked from sin365/AxibugEmuOnline
120 lines
5.1 KiB
C#
120 lines
5.1 KiB
C#
#region Copyright notice and license
|
|
// Protocol Buffers - Google's data interchange format
|
|
// Copyright 2008 Google Inc. All rights reserved.
|
|
//
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file or at
|
|
// https://developers.google.com/open-source/licenses/bsd
|
|
#endregion
|
|
|
|
using System;
|
|
using System.Collections.Concurrent;
|
|
using static Google.Protobuf.Reflection.FeatureSet.Types;
|
|
|
|
namespace Google.Protobuf.Reflection
|
|
{
|
|
/// <summary>
|
|
/// A resolved set of features for a file, message etc.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Only features supported by the C# runtime are exposed; currently
|
|
/// all enums in C# are open, and we never perform UTF-8 validation.
|
|
/// If either of those features are ever implemented in this runtime,
|
|
/// the feature settings will be exposed as properties in this class.
|
|
/// </remarks>
|
|
internal sealed class FeatureSetDescriptor
|
|
{
|
|
private static readonly ConcurrentDictionary<FeatureSet, FeatureSetDescriptor> cache = new();
|
|
|
|
// Note: this approach is deliberately chosen to circumvent bootstrapping issues.
|
|
// This can still be tested using the binary representation.
|
|
// TODO: Generate this code (as a partial class) from the binary representation.
|
|
private static readonly FeatureSetDescriptor edition2023Defaults = new FeatureSetDescriptor(
|
|
new FeatureSet
|
|
{
|
|
EnumType = EnumType.Open,
|
|
FieldPresence = FieldPresence.Explicit,
|
|
JsonFormat = JsonFormat.Allow,
|
|
MessageEncoding = MessageEncoding.LengthPrefixed,
|
|
RepeatedFieldEncoding = RepeatedFieldEncoding.Packed,
|
|
Utf8Validation = Utf8Validation.Verify,
|
|
});
|
|
private static readonly FeatureSetDescriptor proto2Defaults = new FeatureSetDescriptor(
|
|
new FeatureSet
|
|
{
|
|
EnumType = EnumType.Closed,
|
|
FieldPresence = FieldPresence.Explicit,
|
|
JsonFormat = JsonFormat.LegacyBestEffort,
|
|
MessageEncoding = MessageEncoding.LengthPrefixed,
|
|
RepeatedFieldEncoding = RepeatedFieldEncoding.Expanded,
|
|
Utf8Validation = Utf8Validation.None,
|
|
});
|
|
private static readonly FeatureSetDescriptor proto3Defaults = new FeatureSetDescriptor(
|
|
new FeatureSet
|
|
{
|
|
EnumType = EnumType.Open,
|
|
FieldPresence = FieldPresence.Implicit,
|
|
JsonFormat = JsonFormat.Allow,
|
|
MessageEncoding = MessageEncoding.LengthPrefixed,
|
|
RepeatedFieldEncoding = RepeatedFieldEncoding.Packed,
|
|
Utf8Validation = Utf8Validation.Verify,
|
|
});
|
|
|
|
internal static FeatureSetDescriptor GetEditionDefaults(Edition edition) =>
|
|
edition switch
|
|
{
|
|
Edition.Proto2 => proto2Defaults,
|
|
Edition.Proto3 => proto3Defaults,
|
|
Edition._2023 => edition2023Defaults,
|
|
_ => throw new ArgumentOutOfRangeException($"Unsupported edition: {edition}")
|
|
};
|
|
|
|
// Visible for testing. The underlying feature set proto, usually derived during
|
|
// feature resolution.
|
|
internal FeatureSet Proto { get; }
|
|
|
|
/// <summary>
|
|
/// Only relevant to fields. Indicates if a field has explicit presence.
|
|
/// </summary>
|
|
internal FieldPresence FieldPresence => Proto.FieldPresence;
|
|
|
|
/// <summary>
|
|
/// Only relevant to fields. Indicates how a repeated field should be encoded.
|
|
/// </summary>
|
|
internal RepeatedFieldEncoding RepeatedFieldEncoding => Proto.RepeatedFieldEncoding;
|
|
|
|
/// <summary>
|
|
/// Only relevant to fields. Indicates how a message-valued field should be encoded.
|
|
/// </summary>
|
|
internal MessageEncoding MessageEncoding => Proto.MessageEncoding;
|
|
|
|
private FeatureSetDescriptor(FeatureSet proto)
|
|
{
|
|
Proto = proto;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns a new descriptor based on this one, with the specified overrides.
|
|
/// Multiple calls to this method that produce equivalent feature sets will return
|
|
/// the same instance.
|
|
/// </summary>
|
|
/// <param name="overrides">The proto representation of the "child" feature set to merge with this
|
|
/// one. May be null, in which case this descriptor is returned.</param>
|
|
/// <returns>A descriptor based on the current one, with the given set of overrides.</returns>
|
|
public FeatureSetDescriptor MergedWith(FeatureSet overrides)
|
|
{
|
|
if (overrides is null)
|
|
{
|
|
return this;
|
|
}
|
|
|
|
// Note: It would be nice if we could avoid cloning unless
|
|
// there are actual changes, but this won't happen that often;
|
|
// it'll be temporary garbage.
|
|
var clone = Proto.Clone();
|
|
clone.MergeFrom(overrides);
|
|
return cache.GetOrAdd(clone, clone => new FeatureSetDescriptor(clone));
|
|
}
|
|
}
|
|
}
|