Skip to main content

Packets

Under Construction

While a struct may reorganize it layout on memory in unexpected ways, packets are made to be a exact 1:1 map of it implementation to memory.

Packets are designed to not just have total precision on it size in memory as too allow the user to have full controll of the layout of all the bits stored on it.


Implementation and Usage

Packets can be implemented as structs, using the @packed attribute as following:

@packed(8) struct MyDinner {
bool hasFork
bool hasSpoon
bool hasKnife
bool hasPlate
u4 hungerLevel
}

The parameter x in @packed(x) indicates the total size, in bits, of the object in memory. The parameter is, however, optional and will be automatically calculated if not provided.
Inside the packet, you can include primitives and other structures.

Packets are used at the same way as structures:

let MyDinner dinner = MyDinner {
hasFork: true,
hasSpoon: true,
hasKnife: true,
hasPlate: false,
hungerLevel: 10
}

A constructor can also be implemented to make the process easy.

and you can use the dot operator (.) to acess it fields:

import from Std.Console

if (!dinner.hasFork) writeLn("Comrade doesn't have a fork!");
if (!dinner.hasSpoon) writeLn("Comrade doesn't have a spoon!");
if (!dinner.hasKnife) writeLn("Comrade doesn't have a knife!");
if (!dinner.hasPlate) writeLn("Comrade doesn't have a plate!");

if (!dinner.hungerLevel > 10) writeLn("They're starving!!!!");
elif (!dinner.hungerLevel > 5) writeLn("They're hungry!");
Console Output
Comrade doesn't have a plate!
They're hungry!

Manually Modifying Memory Layout

Sometimes, is necessary to declarate exactly how the memory is organized inside a package. For this, the standard library defines with the @packed attribute, the attributes @off, @lay and @pad (abreviations for offset, layout and padding, respectivelly).

They're used to define the positions and sizes of the next fields inside the structure. \

  • @off(x) defines the position of the field based on the origin of x bits;
  • @lay(r) defines the range r of the value, in bits, based on the origin;
  • @pad(r) defines a relative padding left and right based on the range r.

As instance, let's suppose we have the following structure layout for a page of a table:

bytes:0..444..1010..1515..32
data:tag (enum)active (bool)reserved (void)name (5 * u8)index (u16)

As the data follows a structure with specific defined fields, plus there are some values that are not 8-bit alligned, packets should be used to represent this table. A representation of this table should be:

### The range, in bits, are:
- tag: 0 .. 64
- active: 64
- reserved: 64 .. 80
- name: 80 .. 120
- index: 120 .. 256
###
@public @packed struct TablePage {
@lay(..8) Tag tag
bool active # alignment of 1-bits
@off(80)
StringBuffer(5) name # alignment of 8-bits * 5
u16 index # alignment of 16-bits
}

It is also possible to use bytes instead of bits with the range expression's step value. Bothe @lay and @pad attributes will use the step value as a multiplier. e.g.:

# No need to count the bits, as we are using bytes!

@public @packed struct TablePage {
@lay(..4) Tag tag
bool active # alignment of 1-bits
@off(10)
StringBuffer(5) name # alignment of 8-bits * 5
u16 index # alignment of 16-bits
}