108 lines
6.6 KiB
C#
108 lines
6.6 KiB
C#
using System;
|
|
|
|
namespace AyCode.Core.Serializers.Attributes;
|
|
|
|
/// <summary>
|
|
/// Marks a class or struct for Source Generator based binary serialization.
|
|
/// When applied, the Source Generator creates optimized serialize/deserialize methods at compile
|
|
/// time, eliminating the need for runtime reflection or compiled expressions.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// <para>If this attribute is not present, the serializer falls back to the existing
|
|
/// compiled-expression-based approach which works for all types.</para>
|
|
///
|
|
/// <para><b>Feature flag semantics</b> — each <c>Enable*Feature</c> ctor parameter controls whether
|
|
/// the corresponding code-block is <i>emitted</i> by the source generator, NOT whether the feature
|
|
/// is <i>active</i> at runtime:</para>
|
|
/// <list type="bullet">
|
|
/// <item><b><c>true</c> (default):</b> the SGen-emitted writer / reader / scan code <i>includes</i>
|
|
/// the feature's branch. Runtime activation is then governed by the matching
|
|
/// <c>AcBinarySerializerOptions</c> setting (e.g. <c>UseStringInterning</c>,
|
|
/// <c>ReferenceHandling</c>, <c>PropertyFilter</c>, <c>UseMetadata</c>). The developer keeps the
|
|
/// choice per-call by setting the options accordingly.</item>
|
|
/// <item><b><c>false</c>:</b> the corresponding code-block is <i>omitted</i> from the generated
|
|
/// output entirely. Slightly leaner hot-path (fewer branches, less i-cache pressure on the JIT'd
|
|
/// bodies), but the feature is <i>permanently off</i> for this type regardless of runtime options.
|
|
/// A matching <c>AcBinarySerializerOptions</c> setting is silently ignored for this specific type.</item>
|
|
/// </list>
|
|
///
|
|
/// <para>Set a flag to <c>false</c> only when you can guarantee no consumer will ever need that
|
|
/// feature on this type AND the marginal hot-path speedup matters for the workload. Otherwise
|
|
/// leave it at the default <c>true</c>.</para>
|
|
/// </remarks>
|
|
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, Inherited = false, AllowMultiple = false)]
|
|
public sealed class AcBinarySerializableAttribute : Attribute
|
|
{
|
|
public bool EnableMetadataFeature { get; }
|
|
|
|
/// <summary>
|
|
/// When <c>true</c> (default): the SGen-emitted code recognizes the type's tracking-Id property
|
|
/// and emits Id-keyed reference deduplication support, active when <c>ReferenceHandling</c> is
|
|
/// <c>OnlyId</c> or <c>All</c>.
|
|
/// <para>When <c>false</c>: Id-tracking emit is skipped entirely. <b>Significantly reduces
|
|
/// scan-pass cost</b> — the per-instance <c>wrapper.TryTrack*</c> call + <c>IdentityMap</c>
|
|
/// lookup is one of the dominant scan-phase costs. Combined with <c>EnableRefHandlingFeature
|
|
/// = false</c>, the scan body for this type collapses to near-no-op. Reader-side
|
|
/// <c>ObjectRefFirst</c> / <c>ObjectRef</c> case-emit also strips when the child subtree's
|
|
/// tracking is provably absent. The runtime <c>ReferenceHandling</c> option is silently
|
|
/// ignored for instances of this type. Use only when this type is never shared by Id (e.g.
|
|
/// immutable value-DTO, single-use message payload, append-only log entry).</para>
|
|
/// </summary>
|
|
public bool EnableIdTrackingFeature { get; }
|
|
|
|
/// <summary>
|
|
/// Controls emit of this type's non-IId hash-based reference tracking (self-registration in the
|
|
/// scan pass, paired with runtime <c>ReferenceHandling</c>). Scope: ONLY this type's self-tracking
|
|
/// — does NOT govern marker dispatch for child properties (child marker emit follows the child
|
|
/// type's own facts, symmetric writer/reader). See class remarks for the general flag semantics.
|
|
/// </summary>
|
|
public bool EnableRefHandlingFeature { get; }
|
|
|
|
/// <summary>
|
|
/// When <c>true</c> (default): the SGen-emitted code emits string-interning support for
|
|
/// intern-eligible properties — <c>context.ScanInternString(str)</c> in the scan pass and
|
|
/// <c>StringInterned</c> / <c>StringInternFirstSmall</c> / <c>StringInternFirstMedium</c>
|
|
/// case-emit in the reader.
|
|
/// <para>When <c>false</c>: both emit blocks are omitted. <b>Significantly reduces scan-pass
|
|
/// cost</b> — string-property iteration with <c>IdentityMap</c> lookup is eliminated entirely
|
|
/// (often the heaviest scan-phase work on string-rich DTOs). The writer's per-property
|
|
/// <c>StringInternEligible</c> flag is always <c>false</c> for this type, so plan-entry
|
|
/// consumption never fires. Reader switch dispatch shrinks by 3 cases per string property
|
|
/// (smaller jump table, better branch predictor). The runtime <c>UseStringInterning</c> option
|
|
/// is silently ignored for instances of this type. Use only when this type's strings have low
|
|
/// intern-yield (unique per instance — Ids, GUIDs, free-text, never-repeated content).</para>
|
|
/// </summary>
|
|
public bool EnableInternStringFeature { get; }
|
|
|
|
/// <summary>
|
|
/// When <c>true</c> (default): the SGen-emitted writer/scan code includes the per-property
|
|
/// <c>HasPropertyFilter</c> branch + filter-context allocation + lambda-call. Required for runtime
|
|
/// <see cref="AyCode.Core.Serializers.Binaries.BinaryPropertyFilter"/> to take effect on this type.
|
|
/// <para>When <c>false</c>: the SGen-emitted writer/scan code <b>omits</b> the filter check entirely
|
|
/// for every property of this type — leaner generated code on the hot path. Use this when the
|
|
/// type is never serialized with a property-filter (typical for high-throughput message types).
|
|
/// Filter callbacks set on <c>AcBinarySerializerOptions.PropertyFilter</c> will be silently ignored
|
|
/// for this type's properties — only set <c>false</c> if you can guarantee no consumer relies on
|
|
/// per-property filtering for this specific type.</para>
|
|
/// </summary>
|
|
public bool EnablePropertyFilterFeature { get; }
|
|
public bool EnablePolymorphDetectFeature { get; }
|
|
|
|
public AcBinarySerializableAttribute() : this(true)
|
|
{
|
|
}
|
|
|
|
public AcBinarySerializableAttribute(bool enableAllFeatures) : this(enableAllFeatures, enableAllFeatures, enableAllFeatures, enableAllFeatures, enableAllFeatures, enableAllFeatures)
|
|
{ }
|
|
|
|
public AcBinarySerializableAttribute(bool enableMetadataFeature, bool enableIdTrackingFeature, bool enableRefHandlingFeature, bool enableInternStringFeature, bool enablePropertyFilterFeature, bool enablePolymorphDetectFeature)
|
|
{
|
|
EnableMetadataFeature = enableMetadataFeature;
|
|
EnableIdTrackingFeature = enableIdTrackingFeature;
|
|
EnableRefHandlingFeature = enableRefHandlingFeature;
|
|
EnableInternStringFeature = enableInternStringFeature;
|
|
EnablePropertyFilterFeature = enablePropertyFilterFeature;
|
|
EnablePolymorphDetectFeature = enablePolymorphDetectFeature;
|
|
}
|
|
}
|