Thanks @waqar144, yeah I was a bit unclear I should have said that I’m not trying to solve a specific issue, I’m trying to learn how to implement this specific variable size memory layout for iteration.
I was also describing a simplified version, but this is the final form of the data it just needs to iterated over in this exact order. Also this trivial example can be solved with static types using a bit of preprocessing of the data, but I have less trivial example in full implementation.
I’m new to Odin, so after a lot of segmentation fault’s, I got a minimal working example. If anyone knows the reason why using [8]u8 size of rawptr with transmuting to the Layout_Proc works, but taking raw_data from the same range and transmuting to Layout_Proc results in segmentation fault. Looking at docs it says that “A procedure type is internally a pointer to a procedure in memory”, I’m also not sure if I’m taking the right memory address in the first place.
This is the proof of concept code, it is unsafe and handles zero edge cases, I would be grateful for any pointers to all the things I’m doing wrong in here and what are some common approaches for handling this use case:
package tests
import "core:testing"
@(test)
packed_data :: proc(t: ^testing.T) {
pool := new_style_pool()
m := Margin_Start {
top = 2,
left = 4,
}
add_style_layout(pool, m, margin_start)
style_data, layout_proc := get_style_layout(pool)
change_layout := layout_proc(style_data)
testing.expect_value(t, change_layout, Change_Layout{add_x = m.left, add_y = m.top})
}
Style_Pool :: struct {
cursor: u32,
data: [dynamic]u8,
}
new_style_pool :: proc() -> ^Style_Pool {
return new_clone(Style_Pool{cursor = 0, data = make([dynamic]u8)})
}
add_style_layout :: proc(
pool: ^Style_Pool,
style_data: $Data,
layout_proc: proc(style_data: ^Data) -> Change_Layout,
) {
append(&pool.data, size_of(Data))
data_slice := transmute([size_of(Data)]u8)style_data
append(&pool.data, ..data_slice[:])
layout_proc_slice := transmute([size_of(Layout_Proc)]u8)layout_proc
append(&pool.data, ..layout_proc_slice[:])
}
get_style_layout :: proc(pool: ^Style_Pool) -> (rawptr, Layout_Proc) {
style_data_size := u32(pool.data[pool.cursor])
pool.cursor += 1
style_data := raw_data(pool.data[pool.cursor:pool.cursor + style_data_size])
pool.cursor += style_data_size
pool_layout_proc_slice := [size_of(Layout_Proc)]u8{}
for i in 0 ..< u32(size_of(Layout_Proc)) {
pool_layout_proc_slice[i] = pool.data[pool.cursor + i]
}
/* Segmentation fault.
layout_proc := transmute(Layout_Proc)raw_data(
pool.data[pool.cursor:pool.cursor + size_of(Layout_Proc)],
)*/
layout_proc := transmute(Layout_Proc)pool_layout_proc_slice
pool.cursor += size_of(Layout_Proc)
return style_data, layout_proc
}
Layout_Proc :: #type proc(style_data: rawptr) -> Change_Layout
Change_Layout :: struct {
add_x: u8,
add_y: u8,
}
Margin_Start :: struct {
top: u8,
left: u8,
}
margin_start :: proc(m: ^Margin_Start) -> Change_Layout {
return Change_Layout{add_x = m.left, add_y = m.top}
}
Edit: Just realized that, I should be casting raw_data to a pointer of Layout_Proc and then de-referencing it.
get_style_layout :: proc(pool: ^Style_Pool) -> (rawptr, Layout_Proc) {
style_data_size := u32(pool.data[pool.cursor])
pool.cursor += 1
style_data := raw_data(pool.data[pool.cursor:pool.cursor + style_data_size])
pool.cursor += style_data_size
layout_proc := cast(^Layout_Proc)raw_data(
pool.data[pool.cursor:pool.cursor + size_of(Layout_Proc)],
)
pool.cursor += size_of(Layout_Proc)
return style_data, layout_proc^
}