Skip to content

feat: DevEx P0 quick wins — TryFormat, AsTrimmedSpan, header helpers#157

Merged
pedrosakuma merged 1 commit into
mainfrom
feat/devex-p0-quick-wins
Apr 25, 2026
Merged

feat: DevEx P0 quick wins — TryFormat, AsTrimmedSpan, header helpers#157
pedrosakuma merged 1 commit into
mainfrom
feat/devex-p0-quick-wins

Conversation

@pedrosakuma
Copy link
Copy Markdown
Owner

Closes #153 #155 #156.

Three additive DevEx features identificadas no review pós-1.3.0 contra o consumer real (SbeB3UmdfConsumer). Todas eliminam alocações ou constantes hardcoded em hot path do consumer. Emit-time only, sem custo runtime para call sites existentes.

#155AsTrimmedSpan() em InlineArray char types

Consumer fazia msg.Symbol.ToString().Trim() (2 allocs por leitura) para FIX padding. Agora:

ReadOnlySpan<byte> trimmed = msg.Symbol.AsTrimmedSpan();  // 0 alloc, sem \0 e sem espaços trailing

#153ISpanFormattable em char types e decimal composites

Span<char> buf = stackalloc char[64];
Utf8.TryWrite(buf, $"trade {trade.Symbol} @ {trade.Price}", out _);  // zero alloc

Implementa TryFormat + ToString(format, provider) (IFormattable).

#156 — Helpers estáticos no header composite

Consumer hardcoda SbeHeaderSize = 8 e lê templateId via offset mágico. Agora:

if (MessageHeader.TryReadTemplateId(buf, out ushort tid)) { ... }
MessageHeader.TryReadHeader(buf, out var bl, out var tid, out var sid, out var ver);

Detecção: composite cujo nome bate (ordinal-case-insensitive) com SchemaContext.HeaderType, e que tem os 4 campos padrão (BlockLength/TemplateId/SchemaId/Version). Os helpers delegam às properties — endian conversion e headerTypes customizados são respeitados.

Testes

10 novos integration tests em DevExFeatureTests.cs, snapshot atualizado em TypesCodeGenerator.Composite.MessageHeader.verified.txt. 187 + 138 verdes.

Versão

Bump para 1.4.0 (3 features aditivas, sem break).

Não inclui

#154 (foreach enumerator para groups) — fica em PR próprio, é mudança maior no pipeline de AppendReadGroups.

…153 #155 #156)

Three additive features identified in the post-1.3.0 DevEx review against
the real-world SbeB3UmdfConsumer. All three eliminate allocations or
hardcoded constants on consumer hot paths — emit-time changes only, no
codegen size or runtime cost change for existing call sites.

#155 - AsTrimmedSpan() on InlineArray char types
  Consumers of FIX-style space-padded fields (Symbol, Currency, ISIN)
  were forced into msg.Field.ToString().Trim() — two allocations per
  read on hot path. AsTrimmedSpan() additionally strips trailing
  spaces beyond what AsSpan() already trimmed (\0).

#153 - ISpanFormattable on char types and decimal composites
  - Char types implement TryFormat using the schema's
    characterEncoding (Latin1/UTF-8) over AsTrimmedSpan().
  - Decimal composites use the existing Decimals constant for a
    default format string (e.g. F4) so consumers get correctly-scaled
    output without allocating in string.Create / Utf8.TryWrite paths.
  - Both also implement ToString(format, provider) for IFormattable.

#156 - Static header read helpers on the messageHeader composite
  Consumers customizing dispatch were hardcoding 'SbeHeaderSize = 8'
  and reading the templateId via MemoryMarshal.Read at offset 2 — magic
  numbers that break if the schema customizes headerType. Now the
  generated header composite (detected via context.HeaderType,
  case-insensitive) exposes:
    public static bool TryReadTemplateId(ReadOnlySpan<byte>, out ushort)
    public static bool TryReadHeader(ReadOnlySpan<byte>, out blockLength,
                                     out templateId, out schemaId, out version)
  Both delegate to the field accessors, so endian conversion and any
  custom headerType field set are handled correctly.

Detection: emit gate is the ordinal-case-insensitive name match between
the composite name and SchemaContext.HeaderType, plus presence of all
four standard fields (BlockLength/TemplateId/SchemaId/Version).

Tests: 10 new integration tests in DevExFeatureTests.cs covering all
three features. Snapshot updated for TypesCodeGenerator MessageHeader
composite.

187 + 138 tests green. Bumps to 1.4.0.

Closes #153, #155, #156. #154 (foreach enumerator) remains in P0
backlog — separate PR.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@pedrosakuma pedrosakuma merged commit df2ad13 into main Apr 25, 2026
1 check passed
@pedrosakuma pedrosakuma deleted the feat/devex-p0-quick-wins branch April 25, 2026 18:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ISpanFormattable / TryFormat on InlineArray char types and decimal composites

2 participants