I'm implementing GlobalAlloc to always align allocations on 4096-byte boundaries, and for sizes to be a multiple of 64 bytes. This will provide better interoperability with OpenCL, specifically zero-copy-buffers with Intel graphics.

The documentation and source of AllocRef (implemented by System) says the return value for alloc in System is Result<NonNull<u8>, AllocErr>. However, the compiler complains about mismatched types. Pretending that alloc indeed returns *mut u8 and programming as such compiles, but now the IDE (IntelliJ) complains.

Because I'm using the nightly build of Rust, and am very new to Rust, I can't tell if this is simply due to outdated documentation and installed source, a bug in the IDE, or something else that i don't understand.

#![feature(allocator_api)]

use std::alloc::System;
use std::alloc::{handle_alloc_error, AllocRef, GlobalAlloc, Layout};
use std::ptr::NonNull;

struct OpenCLConsideringAlloc;

unsafe impl GlobalAlloc for OpenCLConsideringAlloc {
    unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
        match System.alloc(to_ocl_considering_layout(layout)) {
            Ok(v) => v.as_ptr(),
            Err(e) => match System.alloc(layout) {
                Ok(ptr) => ptr.as_ptr(),
                Err(e) => handle_alloc_error(layout),
            },
        }
    }

    unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
        System.dealloc(
            NonNull::new_unchecked(ptr),
            to_ocl_considering_layout(layout),
        );
    }

    unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
        match System.alloc_zeroed(to_ocl_considering_layout(layout)) {
            Ok(ptr) => ptr.as_ptr(),
            Err(e) => match System.alloc_zeroed(layout) {
                Ok(ptr) => ptr.as_ptr(),
                Err(e) => handle_alloc_error(layout),
            },
        }
    }

    unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
        match System.realloc(
            NonNull::new_unchecked(ptr),
            to_ocl_considering_layout(layout),
            new_size,
        ) {
            Ok(ptr) => ptr.as_ptr(),
            Err(e) => match System.realloc(NonNull::new_unchecked(ptr), layout, new_size) {
                Ok(ptr) => ptr.as_ptr(),
                Err(e) => handle_alloc_error(layout),
            },
        }
    }
}

//Attempts to round-up size up to a multiple of 64, forces 4096-byte alignment for large
//allocations, 64-byte alignment for intermediate sizes, default for small allocations.
#[inline]
fn to_ocl_considering_layout(any_layout: Layout) -> Layout {
    let alignment: usize = match any_layout.size() {
        0..=1024 => any_layout.align(),
        1025..=65536 => 64,
        _ => 4096
    };
    match Layout::from_size_align(
        ((any_layout.size() as i64 + 63_i64) & -64_i64) as usize,
        alignment
    ) {
        Ok(layout) => layout,
        Err(e) => any_layout,
    }
}

#[global_allocator]
static GLOBAL: OpenCLConsideringAlloc = OpenCLConsideringAlloc;

Compiler error:

error[E0308]: mismatched types
  --> src/lib.rs:12:13
   |
11 |         match System.alloc(to_ocl_considering_layout(layout)) {
   |               ----------------------------------------------- this expression has type `*mut u8`
12 |             Ok(v) => v.as_ptr(),
   |             ^^^^^ expected *-ptr, found enum `std::result::Result`
   |
   = note: expected raw pointer `*mut u8`
                     found enum `std::result::Result<_, _>`

The implementation of System::alloc:

unsafe fn alloc(&mut self, layout: Layout) -> Result<NonNull<u8>, AllocErr> {
    NonNull::new(GlobalAlloc::alloc(self, layout)).ok_or(AllocErr)
}

Output of rustup show:

Default host: x86_64-pc-windows-gnu
rustup home:  C:\Users\username\.rustup

nightly-x86_64-pc-windows-gnu (default)
rustc 1.43.0-nightly (6d0e58bff 2020-02-23)
0

There are 0 best solutions below