A Ruby DSL for generating marshalable structured data easily compatable with statically allocated C systems. Currently, it prefers simplicity and predictability over speed.
malloc is a huge pain when you only have 16K of RAM.
There's currently a (single) example in this project. To run it, do this:
git clone git://github.com/sw17ch/cauterize.git cd cauterize bundle install cd example sh build.sh
If this completes without error, then you should find a bunch of generated code
in cauterize_output. Look at the structures and enumerations defined in the
example_project.h file. Also look at how the
functions are organized and named.
Once you've looked at this, take a look at
example_project.c. This will show
you the exact mechanism used to package and unpackage different structures.
cauterize.c are used as iterators over C buffers. They are
used to abstract the process of packaging and unpackaging different elements.
There are 7 fundamental classes of types in Cauterize. These types have several characteristics:
- They can be copied with
- They do not attempt to cover the concept of indirection or pointers.
- They are simple.
- They cannot be defined recursively.
- 1 Byte Primitives
:bool- a boolean value
:int8- a signed, 8 bit value
:uint8- an unsigned, 8 bit value
- 2 Byte Primitives
:int16- a signed, 16 bit value
:uint16- an unsigned, 16 bit value
- 4 Byte Primitives
:int32- a signed, 32 bit value
:uint32- an unsigned, 32 bit value
:float32- a 32 bit floating point value
- 8 Byte Primitives
:int64- a signed, 64 bit value
:uint64- an unsigned, 64 bit value
:float64- a 64 bit floating point value
Scalars are any type that corresponds to a C scalar value. That is, something
that can be defined with the native types (
short, etc). It is
highly recommended that these ONLY ever use values from
ensures that the sizes of these scalars will be consistent across platforms.
Scalars can be defined simply by giving them a name that corresponds to a type
Enumerations correspond almost exactly to C enumerations. They are a list of names. When appropriate, a specific scalar value may also be specified. If no scalar is specified, enumerations will be represented in order from 0.
enumeration(:color) do |e| e.value :red e.value :blue e.value :green end enumeration(:days_of_week) do |e| e.value :sunday, 100 e.value :monday, 101 e.value :tuesday, 102 e.value :wednesday, 103 e.value :thursday, 104 e.value :friday, 105 e.value :saturday, 106 end
Fixed arrays are arrays that only ever make sense when they are full. An example of an array with this property is a MAC Address. MAC addresses are always 6 bytes. Never more. Never less.
fixed_array(:mac_address) do |a| a.array_type :uint8_t # the type held by the array a.array_size 6 # the number of elements in the array end
Variable Arrays are arrays that have a maximum length, but may not be entirely utilized.
# a way to represent some number of dates/times as 32-bit values variable_array(:datetimes) do |a| a.size_type :uint8_t # WILL BE DEPRECATED a.array_type :int32_t a.array_size 128 end # a string, represented as `int_8`'s, with a maximum length of 32 bytes variable_array(:string_32) do |a| a.size_type :uint8_t # WILL BE DEPRECATED a.array_type :int8_t a.array_size 32 end
Composites are very similar to C structures. They are collections of other types. Each field has a name and may correspond to any other defined type.
composite(:person) do |c| c.field :name, :string_32 c.field :age, :uint8_t c.field :date_of_birth, :uint32_t end
Groups are similar to C unions with one major difference. Each group is comprised of a type tag and a union of the types the union is capable of representing. This is known as a tagged union.
The tag is used to inform the user application what type the union is currently representing. The tag is a special enumeration that is automatically defined.
group(:requests) do |g| c.field :add_user, :add_user_request c.field :get_user, :get_user_request c.field :delete_user, :delete_user_request end group(:responses) do |g| c.field :add_user, :add_user_response c.field :get_user, :get_user_response c.field :delete_user, :delete_user_response end
Groups don't have to specify a data type in all of their fields.
group(:complex) do |g| g.field :a_number, :int32 g.dataless :a_state # no associated data with this alternative end