SkillAgentSearch skills...

PropertyBitPack

This library, PropertyBitPack, is a Roslyn source generator that simplifies the process of defining and managing bit-packed properties in C#. It allows developers to decorate properties with custom attributes to automatically generate efficient bit manipulation code.

Install / Use

/learn @Asaicraft/PropertyBitPack
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

Build NuGet Stats Discord

PropertyBitPack

PropertyBitPack is a Roslyn source generator that simplifies defining and managing bit-packed properties in C#. It allows developers to decorate properties with custom attributes to automatically generate efficient bit manipulation code.

📖 Documentation

Table of Contents

Installation

PropertyBitPack is available as a NuGet package. You can install it using the following command:

dotnet add package PropertyBitPack

Usage

Define Bit-Packed Boolean Properties

By default, boolean properties are stored using at least 1 byte of memory. To reduce memory usage, you can use the BitFieldAttribute to pack multiple bool properties into a single byte.

The following example demonstrates how to define bit-packed boolean properties using the BitFieldAttribute:

using PropertyBitPack;

namespace SomeNamespace;

public partial class BitPackedBools
{
    [BitField]
    public partial bool Bool1 { get; set; }
	
    [BitField]
    public partial bool Bool2 { get; set; }
	
    [BitField]
    public partial bool Bool3 { get; set; }
	
    [BitField]
    public partial bool Bool4 { get; set; }
}

This will generate the following code:

partial class BitPackedBools
{
    private byte _Bool1__Bool2__Bool3__Bool4__;
    public partial bool Bool1
    {
        get
        {
            return ((this._Bool1__Bool2__Bool3__Bool4__ >> 0) & (1)) == 1;
        }
        set
        {
            this._Bool1__Bool2__Bool3__Bool4__ = (byte)(value ? ((this._Bool1__Bool2__Bool3__Bool4__) | (((1 << 1) - 1) << 0)) : (this._Bool1__Bool2__Bool3__Bool4__ & ~(((1 << 1) - 1) << 0)));
        }
    }

    public partial bool Bool2
    {
        get
        {
            return ((this._Bool1__Bool2__Bool3__Bool4__ >> 1) & (1)) == 1;
        }
        set
        {
            this._Bool1__Bool2__Bool3__Bool4__ = (byte)(value ? ((this._Bool1__Bool2__Bool3__Bool4__) | (((1 << 1) - 1) << 1)) : (this._Bool1__Bool2__Bool3__Bool4__ & ~(((1 << 1) - 1) << 1)));
        }
    }

    public partial bool Bool3
    {
        get
        {
            return ((this._Bool1__Bool2__Bool3__Bool4__ >> 2) & (1)) == 1;
        }
        set
        {
            this._Bool1__Bool2__Bool3__Bool4__ = (byte)(value ? ((this._Bool1__Bool2__Bool3__Bool4__) | (((1 << 1) - 1) << 2)) : (this._Bool1__Bool2__Bool3__Bool4__ & ~(((1 << 1) - 1) << 2)));
        }
    }

    public partial bool Bool4
    {
        get
        {
            return ((this._Bool1__Bool2__Bool3__Bool4__ >> 3) & (1)) == 1;
        }
        set
        {
            this._Bool1__Bool2__Bool3__Bool4__ = (byte)(value ? ((this._Bool1__Bool2__Bool3__Bool4__) | (((1 << 1) - 1) << 3)) : (this._Bool1__Bool2__Bool3__Bool4__ & ~(((1 << 1) - 1) << 3)));
        }
    }
}

Define Bit-Packed Properties with Mixed Types

The BitFieldAttribute can also be used to pack multiple properties of different types into a single field. The following example demonstrates how to define bit-packed properties for booleans and a byte using the BitFieldAttribute:

using PropertyBitPack;

namespace SomeNamespace;

public partial class BitPackedBools
{
    [BitField]
    public partial bool Bool1 { get; set; }
	
    [BitField]
    public partial bool Bool2 { get; set; }
	
    [BitField]
    public partial bool Bool3 { get; set; }

    [BitField]
    public partial bool Bool4 { get; set; }

    [BitField]
    public partial byte Byte1 { get; set; }
}

This will generate the following code:

partial class BitPackedBools
{
    private ushort _Bool1__Bool2__Bool3__Bool4__Byte1__;
    public partial bool Bool1
    {
        get
        {
            return ((this._Bool1__Bool2__Bool3__Bool4__Byte1__ >> 0) & (1)) == 1;
        }
        set
        {
            this._Bool1__Bool2__Bool3__Bool4__Byte1__ = (ushort)(value ? ((this._Bool1__Bool2__Bool3__Bool4__Byte1__) | (((1 << 1) - 1) << 0)) : (this._Bool1__Bool2__Bool3__Bool4__Byte1__ & ~(((1 << 1) - 1) << 0)));
        }
    }

    public partial bool Bool2
    {
        get
        {
            return ((this._Bool1__Bool2__Bool3__Bool4__Byte1__ >> 1) & (1)) == 1;
        }
        set
        {
            this._Bool1__Bool2__Bool3__Bool4__Byte1__ = (ushort)(value ? ((this._Bool1__Bool2__Bool3__Bool4__Byte1__) | (((1 << 1) - 1) << 1)) : (this._Bool1__Bool2__Bool3__Bool4__Byte1__ & ~(((1 << 1) - 1) << 1)));
        }
    }

    public partial bool Bool3
    {
        get
        {
            return ((this._Bool1__Bool2__Bool3__Bool4__Byte1__ >> 2) & (1)) == 1;
        }
        set
        {
            this._Bool1__Bool2__Bool3__Bool4__Byte1__ = (ushort)(value ? ((this._Bool1__Bool2__Bool3__Bool4__Byte1__) | (((1 << 1) - 1) << 2)) : (this._Bool1__Bool2__Bool3__Bool4__Byte1__ & ~(((1 << 1) - 1) << 2)));
        }
    }

    public partial bool Bool4
    {
        get
        {
            return ((this._Bool1__Bool2__Bool3__Bool4__Byte1__ >> 3) & (1)) == 1;
        }
        set
        {
            this._Bool1__Bool2__Bool3__Bool4__Byte1__ = (ushort)(value ? ((this._Bool1__Bool2__Bool3__Bool4__Byte1__) | (((1 << 1) - 1) << 3)) : (this._Bool1__Bool2__Bool3__Bool4__Byte1__ & ~(((1 << 1) - 1) << 3)));
        }
    }

    public partial byte Byte1
    {
        get
        {
            return (byte)((this._Bool1__Bool2__Bool3__Bool4__Byte1__ >> 4) & ((1 << 8) - 1));
        }
        set
        {
            const ushort maxValue_ = (1 << 8) - 1;
            var clamped_ = global::System.Math.Min((ushort)(value), maxValue_);
            this._Bool1__Bool2__Bool3__Bool4__Byte1__ = (ushort)((this._Bool1__Bool2__Bool3__Bool4__Byte1__ & ~(((1 << 8) - 1) << 4)) | ((clamped_ & ((1 << 8) - 1)) << 4));
        }
    }
}

As you can see, the BitFieldAttribute can pack multiple properties of different types into a single field. In this example, 1 + 1 + 1 + 1 + 8 = 12 bits are packed into a single ushort field.

Define Bit-Packed Properties with Custom Bit Sizes

The BitFieldAttribute can also be used to pack properties with custom bit sizes. The following example demonstrates how to define bit-packed properties with custom bit sizes:

internal sealed partial record RecordExample
{
    [BitField(BitsCount = 4)]
    public partial byte Property1 { get; init; }

    [BitField(BitsCount = 11)]
    public partial int Property2 { get; init; }
}

This will generate the following code:

partial record RecordExample
{
    private ushort _Property1__Property2__;
    public partial byte Property1
    {
        get
        {
            return (byte)((this._Property1__Property2__ >> 0) & ((1 << 4) - 1));
        }
        init
        {
            const ushort maxValue_ = (1 << 4) - 1;
            var clamped_ = global::System.Math.Min((ushort)(value), maxValue_);
            this._Property1__Property2__ = (ushort)((this._Property1__Property2__ & ~(((1 << 4) - 1) << 0)) | ((clamped_ & ((1 << 4) - 1)) << 0));
        }
    }

    public partial int Property2
    {
        get
        {
            return (int)((this._Property1__Property2__ >> 4) & ((1 << 11) - 1));
        }
        init
        {
            const ushort maxValue_ = (1 << 11) - 1;
            var clamped_ = global::System.Math.Min((ushort)(value), maxValue_);
            this._Property1__Property2__ = (ushort)((this._Property1__Property2__ & ~(((1 << 11) - 1) << 4)) | ((clamped_ & ((1 << 11) - 1)) << 4));
        }
    }
}

Generate Custom Field Names

You can also specify a custom field name using the FieldName property of the BitFieldAttribute. The following example demonstrates how to define bit-packed properties with custom field names:

internal sealed partial class NamedFieldExample
{
    [BitField(FieldName = "_another", BitsCount = 9)]
    public partial short Short1 { get; set; }

    [BitField(FieldName = "_another", BitsCount = 9)]
    public partial short Short2 { get; set; }
}

This will generate the following code:

partial class NamedFieldExample
{
    private uint _another;
    public partial short Short1
    {
        get
        {
            return (short)((this._another >> 0) & ((1U << 9) - 1));
        }
        set
        {
            const uint maxValue_ = (1U << 9) - 1;
            var clamped_ = global::System.Math.Min((uint)(value), maxValue_);
            this._another = (uint)((this._another & ~(((1U << 9) - 1) << 0)) | ((clamped_ & ((1U << 9) - 1)) << 0));
        }
    }

    public partial short Short2
    {
        get
        {
            return (short)((this._another >> 9) & ((1U << 9) - 1));
        }
        set
        {
            const uint maxValue_ = (1U << 9) - 1;
            var clamped_ = global::System.Math.Min((uint)(value), maxValue_);
            this._another = (uint)((this._anot

Related Skills

View on GitHub
GitHub Stars18
CategoryDevelopment
Updated6mo ago
Forks0

Languages

JavaScript

Security Score

82/100

Audited on Oct 6, 2025

No findings