Below is an overview of the internal architecture of PropertyBitPack, focusing on how it processes attributes, aggregates bit-packed properties, and generates source code. This documentation is intended for contributors who want to understand or extend the source generator logic.
High-Level Architecture​
PropertyBitPackGeneratorContext(abstract class)- Defines arrays of parsers and generators:
AttributeParsers(implementations ofIAttributeParser)BitFieldPropertyParsers(implementations ofIBitFieldPropertyParser)BitFieldPropertyAggregators(implementations ofIBitFieldPropertyAggregator)PropertySyntaxGenerators(implementations ofIPropertiesSyntaxGenerator)
- Provides methods to:
- Identify candidate attributes
- Parse them into internal
BaseBitFieldPropertyInforepresentations - Aggregate property info into requests (
IGenerateSourceRequest) - Generate final C# source code (
FileGeneratorRequest)
- Defines arrays of parsers and generators:
PropertyBitPackGeneratorContextImplementation- A sealed nested class that constructs these arrays without constructor injection in the typical DI sense.
- Instead, after constructing arrays of parsers/generators, the method
BindToSelf()iterates over each component.- If the component implements
IContextBindable, it callsBindContext(this), providing a direct link to the current context instance.
- If the component implements
PropertyBitPackSourceGenerator : IIncrementalGenerator- Holds a static instance of
PropertyBitPackGeneratorContext. - Uses incremental generation:
- Filters candidate properties via
IsCandidateProperty(...). - For each property, attempts to parse attached attributes.
- Aggregates bit-packed properties.
- Calls context methods to generate final source code.
- Filters candidate properties via
- Holds a static instance of
Parsing Workflow
- Identify partial properties with certain attributes.
- Check if any of the known attribute parsers (
IAttributeParser) match. - Parse them into
BaseBitFieldPropertyInfo. - Aggregate all recognized properties into
IGenerateSourceRequestobjects. - Generate the final
.cssource files (property implementations) viaIPropertiesSyntaxGenerator.
Mermaid Diagram​
flowchart LR
A[IncrementalGenerator] --> B{PropertyBitPackGeneratorContextImplementation}
B -->|BindToSelf| D[IContextBindable?]
B -->|AttributeParsers| C[PropertyDeclaration]
B -->|BitFieldPropertyParsers| E[BaseBitFieldPropertyInfo]
B -->|BitFieldPropertyAggregators| F[IGenerateSourceRequest]
B -->|PropertySyntaxGenerators| G["FileGeneratorRequest (CS)"]
C --> E
E --> F
F --> G
source
flowchart LR
A[IncrementalGenerator] --> B{PropertyBitPackGeneratorContextImplementation}
B -->|BindToSelf| D[IContextBindable?]
B -->|AttributeParsers| C[PropertyDeclaration]
B -->|BitFieldPropertyParsers| E[BaseBitFieldPropertyInfo]
B -->|BitFieldPropertyAggregators| F[IGenerateSourceRequest]
B -->|PropertySyntaxGenerators| G["FileGeneratorRequest (CS)"]
C --> E
E --> F
F --> G
Diagram Explanation:
- IncrementalGenerator filters candidate properties.
- PropertyBitPackGeneratorContextImplementation:
- Holds arrays of parsers/generators.
- Calls
BindToSelf(), so each component that implementsIContextBindablecan access the context.
- The parsers/generators then handle attribute parsing, property analysis, and source code generation.
Notable Classes & Interfaces​
PropertyBitPackGeneratorContextImplementation​
internal sealed class PropertyBitPackGeneratorContextImplementation : PropertyBitPackGeneratorContext
{
public PropertyBitPackGeneratorContextImplementation(
ImmutableArray<IAttributeParser> attributeParsers,
ImmutableArray<IBitFieldPropertyParser> bitFieldPropertyParsers,
ImmutableArray<IBitFieldPropertyAggregator> bitFieldPropertyAggregators,
ImmutableArray<IPropertiesSyntaxGenerator> bitFieldPropertyGenerators
) {
AttributeParsers = attributeParsers;
BitFieldPropertyParsers = bitFieldPropertyParsers;
BitFieldPropertyAggregators = bitFieldPropertyAggregators;
PropertySyntaxGenerators = bitFieldPropertyGenerators;
// Binds the context to all parsers/generators that require it
BindToSelf();
}
internal void BindToSelf()
{
// If any component implements IContextBindable, pass it this context
}
}
- No typical DI constructor injection. The arrays of components are assigned directly, then
BindToSelf()ensures each component can hold a reference to the context if needed.
IContextBindable​
internal interface IContextBindable
{
void BindContext(PropertyBitPackGeneratorContext context);
}
- Components (e.g., parsers, aggregators, syntax generators) implement
IContextBindableto gain access to shared context data or services.
PropertyBitPackSourceGenerator​
- Entry point for incremental generation. Creates a static
_contextusing aPropertyBitPackGeneratorContextBuilder. - Scans the syntax for candidate partial properties, matches attributes, and produces generated
.csfiles.
Customizing Parsers & Generators​
To add or override behavior:
- Implement a new
IAttributeParser,IBitFieldPropertyParser,IBitFieldPropertyAggregator, orIPropertiesSyntaxGenerator. - Attach it to the context builder:
var builder = PropertyBitPackGeneratorContextBuilder.Create(); builder.AttributeParsers.Add(new MyCustomAttributeParser()); builder.BitFieldPropertyParsers.Add(new MyCustomBitFieldParser()); // ... var context = builder.Build(); // Returns PropertyBitPackGeneratorContextImplementation - Use
BindToSelf()to allow each component toBindContext(...)if it implementsIContextBindable.
Summary​
- PropertyBitPack uses a modular approach, allowing you to plug in new attribute parsers, property parsers, aggregators, and syntax generators.
- Context binding is not done through traditional DI constructor injection; instead,
BindToSelf()iterates over all registered components and callsBindContext(this)if they implementIContextBindable. - This design keeps the architecture flexible and straightforward, enabling easy extension for advanced bit-packing scenarios.
For questions or deeper discussion, feel free to join our Discord!