module BinData::BitField

def create_clamp_code(nbits)

def create_clamp_code(nbits)
  min = 0
  max = (1 << nbits) - 1
  clamp = "val = (val < #{min}) ? #{min} : (val > #{max}) ? #{max} : val"
  if nbits == 1
    # allow single bits to be used as booleans
    "val = (val == true) ? 1 : (not val) ? 0 : #{clamp}"
  else
    clamp
  end
end

def define_class(nbits, endian)

def define_class(nbits, endian)
  name = "Bit#{nbits}"
  name += "le" if endian == :little
  unless BinData.const_defined?(name)
    BinData.module_eval <<-END
      class #{name} < BinData::BasePrimitive
        BitField.define_methods(self, #{nbits}, :#{endian})
      end
    END
  end
  BinData.const_get(name)
end

def define_methods(bit_class, nbits, endian)

def define_methods(bit_class, nbits, endian)
  bit_class.module_eval <<-END
    def assign(val)
      #{create_clamp_code(nbits)}
      super(val)
    end
    def do_write(io)
      io.writebits(_value, #{nbits}, :#{endian})
    end
    def do_num_bytes
      #{nbits / 8.0}
    end
    #---------------
    private
    def read_and_return_value(io)
      io.readbits(#{nbits}, :#{endian})
    end
    def sensible_default
      0
    end
  END
end