Несоответствие типов при реализации встроенных трейтов, но это должно быть правильно согласно документации и источнику AllocRef

Я реализую GlobalAlloc, чтобы всегда выравнивать выделения по границам 4096 байт и чтобы размеры были кратны 64 байтам. Это обеспечит лучшую совместимость с OpenCL, в частности буферы нулевого копирования с графикой Intel.

Документация и источник AllocRef (реализованный System) говорят, что возвращаемое значение для alloc в System равно Result<NonNull<u8>, AllocErr>. Однако компилятор жалуется на несоответствие типов. Притворяясь, что alloc действительно возвращает *mut u8, и программирование как таковое компилируется, но теперь IDE (IntelliJ) жалуется.

Поскольку я использую ночную сборку Rust и очень новичок в Rust, я не могу сказать, связано ли это просто с устаревшей документацией и установленным исходным кодом, ошибкой в ​​IDE или чем-то еще, чего я не понимаю. .

#![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;

Ошибка компилятора:

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<_, _>`

реализация System::alloc :

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

Выход 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)

person Tonnz    schedule 26.02.2020    source источник
comment
System реализует AllocRef и GlobalAlloc, оба из которых имеют метод alloc. Вы звоните GlobalAlloc::alloc. На это отвечают ответы Как устранить неоднозначность признаков в Rust?. Если нет, отредактируйте свой вопрос, чтобы объяснить различия. В противном случае мы можем пометить этот вопрос как уже отвеченный.   -  person Shepmaster    schedule 26.02.2020
comment
Дубликат применен к вашему первому методу (я лень все делать).   -  person Shepmaster    schedule 26.02.2020
comment
Да, это он @Shepmaster. Применение вашего предложения (за вычетом случайного изменения System на AllocRef) также дает более полезную ошибку компилятора: error[E0034]: multiple applicable items in scope. Это ответ на мой вопрос, спасибо @Shepmaster и @Stargateur!   -  person Tonnz    schedule 26.02.2020