I have a dst that looks like this:
#[repr(C)]
pub struct RegionRepr {
meta: RegionMeta,
chunks: [ChunkRepr],
}
#[repr(C)]
struct RegionMeta {
pub origin: IVec3,
pub settings: Arc<WorldSettings>, // < this causes a problem
pub state: RegionState,
pub col_len: usize,
pub columns: [ColumnState; 256],
}
struct ChunkRepr {
blocks: // custom data structure
}
I want to combine all the region data into one pointer allocation because the number of chunks is known at initialization time, and to reduce the number of pointer dereferences needed to access chunks. Its' a small optimization, but it will be called millions, or even billions of times so I care.
I am initializing an empty region like so, based on the implementation for Arc<[T]>
:
impl RegionRepr {
pub fn empty(origin: IVec3, settings: Arc<WorldSettings>) -> Box<Self> {
// the length of the regions' chunks buffer.
let len = 16 * 16 * settings.chunks_per_column();
// compute the layout by combining the layouts of the fields.
let layout = Layout::new::<RegionMeta>()
.extend(Layout::array::<ChunkRepr>(len).unwrap())
.unwrap().0.pad_to_align();
let mut region: Box<RegionRepr> = unsafe {
// allocate a pointer for chunks and meta
let raw = ptr::NonNull::new(alloc(layout) as *mut ()).unwrap();
// convert the thin pointer to a fat pointer (slice) and box it
let ptr = NonNull::new(ptr::slice_from_raw_parts_mut(raw.as_ptr().cast::<ChunkRepr>(), len)).unwrap();
Box::from_raw(ptr.as_ptr() as *mut _)
};
// Initialize region metadata
region.meta = RegionMeta {
origin,
col_len: settings.chunks_per_column(),
settings,
state: RegionState::empty(),
columns: [ColumnState::empty(); 256],
};
// initialize chunks
for i in 0..len {
region.chunks[i] = ChunkRepr::empty()
}
region
}
}
However, this code results in a segmentation fault. I found that the segfault goes away and this code runs perfectly if I remove the Arc<WorldSettings>
from the metadata. I've attached links to the playground with examples. Any idea why this occurs, and how I can solve it?