package bitmask import ( "bytes" "encoding/binary" "errors" "math/bits" ) // MaskBit is a flag container. type MaskBit uint /* NewMaskBit is a convenience function. It will return a MaskBit with a (referenced) value of 0, so set your consts up accordingly. It is highly recommended to set this default as a "None" flag (separate from your iotas!) as shown in the example. */ func NewMaskBit() (m *MaskBit) { m = new(MaskBit) return } // NewMaskBitExplicit is like NewMaskBit, but allows you to specify a non-zero (0x0) value. func NewMaskBitExplicit(value uint) (m *MaskBit) { var v MaskBit = MaskBit(value) m = &v return } /* HasFlag is true if m has MaskBit flag set/enabled. THIS WILL RETURN FALSE FOR OR'd FLAGS. For example: flagA MaskBit = 0x01 flagB MaskBit = 0x02 flagComposite = flagA | flagB m *MaskBit = NewMaskBitExplicit(uint(flagA)) m.HasFlag(flagComposite) will return false even though flagComposite is an OR that contains flagA. Use [MaskBit.IsOneOf] instead if you do not desire this behavior, and instead want to test composite flag *membership*. (MaskBit.IsOneOf will also return true for non-composite equality.) To be more clear, if MaskBit flag is a composite MaskBit (e.g. flagComposite above), HasFlag will only return true of ALL bits in flag are also set in MaskBit m. */ func (m *MaskBit) HasFlag(flag MaskBit) (r bool) { var b MaskBit = *m if b&flag == flag { r = true } return } /* IsOneOf is like a "looser" form of [MaskBit.HasFlag] in that it allows for testing composite membership. See [MaskBit.HasFlag] for more information. If composite is *not* an OR'd MaskBit (i.e. it falls directly on a boundary -- 0, 1, 2, 4, 8, 16, etc.), then IsOneOf will behave exactly like HasFlag. If m is a composite MaskBit (it usually is) and composite is ALSO a composite MaskBit, IsOneOf will return true if ANY of the flags set in m is set in composite. */ func (m *MaskBit) IsOneOf(composite MaskBit) (r bool) { var b MaskBit = *m if b&composite != 0 { r = true } return } // AddFlag adds MaskBit flag to m. func (m *MaskBit) AddFlag(flag MaskBit) { *m |= flag return } // ClearFlag removes MaskBit flag from m. func (m *MaskBit) ClearFlag(flag MaskBit) { *m &^= flag return } // ToggleFlag switches MaskBit flag in m to its inverse; if true, it is now false and vice versa. func (m *MaskBit) ToggleFlag(flag MaskBit) { *m ^= flag return } /* Bytes returns the current value of a MasBit as a byte slice (big-endian). If trim is false, b will (probably) be 4 bytes long if you're on a 32-bit size system, and b will (probably) be 8 bytes long if you're on a 64-bit size system. You can determine the size of the resulting slice via (math/)bits.UintSize / 8. If trim is true, it will trim leading null bytes (if any). This will lead to an unpredictable byte slice length in b, but is most likely preferred for byte operations. */ func (m *MaskBit) Bytes(trim bool) (b []byte) { var b2 []byte var size int = bits.UintSize / 8 var err error b2 = make([]byte, size) switch s := bits.UintSize; s { case 32: binary.BigEndian.PutUint32(b2[:], uint32(*m)) case 64: binary.BigEndian.PutUint64(b2[:], uint64(*m)) default: err = errors.New("unsupported Uint/system bit size") panic(err) } if trim { b = bytes.TrimLeft(b2, "\x00") return } else { b = b2 return } return } // Copy returns a pointer to a (new) copy of a MaskBit. func (m *MaskBit) Copy() (newM *MaskBit) { newM = new(MaskBit) *newM = *m return } // Value returns the current raw uint value of a MaskBit. func (m *MaskBit) Value() (v uint) { v = uint(*m) return }