Как создать тип Rust, который может содержать целое число или указатель в пределах размера одного слова? - PullRequest
0 голосов
/ 08 сентября 2018

(Я имею в виду бокс как способ различения целых чисел и указателей во время выполнения. В методике используются некоторые языки программирования для поддержки GC, такие как OCaml . Не тип Rust Box<T>.)

У меня есть список Rust, который выглядит так:

#[derive(Clone, Copy, Debug, PartialEq)]
enum Type<'ts> {
    TVar(usize),
    Constructed(&'ts ConstructedType<'ts>),
}

Насколько я понимаю, структура памяти для этого перечисления будет состоять из двух слов. Один для тега и один для полезной нагрузки. Я хотел бы уместить память в одно слово, если это возможно.

Такие языки, как OCaml , используют технику, называемую «целочисленный бокс», которая использует тот факт, что указатели выровнены. Это означает, что младший бит будет равен 0. Если вы сдвинете биты в вашем целом числе на один пробел влево и установите младший бит вашего целого числа в 1, то вы используете этот бит в качестве тега по цене одного бита целочисленная точность.

Гарантируется ли выравнивание указателей Rust? Как бы я внедрил эту технику для моего типа в Rust?

1 Ответ

0 голосов
/ 08 сентября 2018

Возможно, я не слежу за всем , что вы говорите, но я думаю, что вам нужно union.

#[derive(Clone, Copy, Debug, PartialEq)]
enum Type<'ts> {
    TVar(usize),
    Constructed(&'ts ConstructedType<'ts>),
}

union CompactType<'ts> {
    num: usize,
    ptr: &'ts ConstructedType<'ts>
}

impl<'ts> From<CompactType<'ts>> for Type<'ts> {
    fn from(compact: CompactType<'ts>) -> Type<'ts> {
        unsafe {
            if compact.num & 1 == 1 {
                Type::TVar(compact.num >> 1)
            } else {
                Type::Constructed(compact.ptr)
            }
        }
    }
}

Обратите внимание, что доступ к членам union небезопасен,и вы должны убедиться, что все инварианты соблюдаются.Например, вы должны явно проверить, что CompactType s правильно созданы со значениями в пределах диапазона, и предотвратить возможность создания объектов без такой проверки.

Я бы предложил добавить конструкторфункции CompactType, которые возвращают Result или Option, если вы пытаетесь использовать слишком большое число или указатель на тип, который не выровнен должным образом.Когда TryFrom функция стабилизируется, вы можете использовать это, но в то же время:

enum CompactConvertError {
    NumTooBig(String),
    PtrNotAligned(String),
}

impl<'ts> Type<'ts> {
    fn to_compact(&self) -> Result<CompactType<'ts>, CompactConvertError> {
        match self {
            Type::TVar(num) => {
                if num >> (mem::size_of::<usize>() * 8 - 1) == 1 {
                    Err(CompactConvertError::NumTooBig(
                        String::from("The last bit of the usize cannot be used here"))
                    )
                } else {
                    Ok(CompactType { num: num << 1 | 1usize })
                }   
            },
            Type::Constructed(c) => {
                if mem::align_of_val(*c) % 2 == 1 {
                    Err(CompactConvertError::PtrNotAligned(
                        String::from("The pointer must be to a type with even alignment"))
                    )
                } else {
                    Ok(CompactType { ptr: c })
                }
            }
        }
    } 
}

Это должно быть достаточно гибким, чтобы заменить ConstructedType параметром универсального типа.Единственное ограничение заключается в том, что вы не должны изменять его со ссылкой на собственное значение, иначе вам придется беспокоиться о его правильном отбрасывании - что пока нельзя сделать для типа union в стабильном Rust.

Что касается выравнивания, если ConstructedType имеет размер всего 1 байт, вам необходимо добавить выравнивание, чтобы убедиться, что оно выполняется только по четному байту, в противном случае Rust может выбрать более плотную упаковку:

#[align(2)]
struct ConstructedType<'ts> { 
    // ...
}

Определенно не добавляйте #[align(2)], если размер больше 2 байтов.Возможно, кто-то еще может посоветовать, как сделать эту часть более надежной.

...