AyCode.Core/AyCode.Core/Serializers/Attributes/AcBinarySerializableAttribu...

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;
}
}