如何创建一个可以在单个单词大小内保存整数或指针的 Rust 类型?

Cal*_*mer 3 optimization ocaml pointers rust union-types

(I\xe2\x80\x99m 指的是装箱作为在运行时区分整数和指针的一种方式。一种技术使用一些编程语言来帮助 GC,如OCaml。不是 RustBox<T>类型。)

\n\n

我有一个 Rust 枚举,如下所示:

\n\n
#[derive(Clone, Copy, Debug, PartialEq)]\nenum Type<\'ts> {\n    TVar(usize),\n    Constructed(&\'ts ConstructedType<\'ts>),\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

据我了解,这个枚举的内存布局将是两个单词。一份用于标签,一份用于有效负载。如果可能的话,我想用一个词来表达记忆。

\n\n

像OCaml这样的语言使用一种名为 \xe2\x80\x9cinteger boxing\xe2\x80\x9d 的技术,它利用了指针对齐的事实。这意味着最低位将为 0。如果将整数中的位向左移动一位并将整数的最低位设置为 1,则您\xe2\x80\x99 将使用该位作为标记,但代价是一位整数精度。

\n\n

Rust 指针保证对齐吗?我如何在 Rust 中为我的类型实现这种技术?

\n

Pet*_*all 5

我可能没有听懂你所说的一切union,但我认为你需要一个.

\n\n
#[derive(Clone, Copy, Debug, PartialEq)]\nenum Type<\'ts> {\n    TVar(usize),\n    Constructed(&\'ts ConstructedType<\'ts>),\n}\n\nunion CompactType<\'ts> {\n    num: usize,\n    ptr: &\'ts ConstructedType<\'ts>\n}\n\nimpl<\'ts> From<CompactType<\'ts>> for Type<\'ts> {\n    fn from(compact: CompactType<\'ts>) -> Type<\'ts> {\n        unsafe {\n            if compact.num & 1 == 1 {\n                Type::TVar(compact.num >> 1)\n            } else {\n                Type::Constructed(compact.ptr)\n            }\n        }\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

请注意,访问 a 的成员union是不安全的,您必须确保强制执行所有不变量。例如,您必须显式检查是否CompactType使用范围内的值正确创建了 s,并防止在不经过这些检查的情况下构造对象的可能性。

\n\n

我建议向 中添加构造函数CompactType,该函数返回 aResult或 an Option,以防您尝试使用太大的数字或指向未正确对齐的类型的指针。当该TryFrom功能稳定后,您可以使用它,但与此同时:

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

这应该足够灵活,可以替换ConstructedType为泛型类型参数。唯一的限制是你不应该将它从引用更改为拥有的值,否则你将不得不担心如何正确删除它\xe2\x80\x94,这对于union稳定 Rust 中的类型尚无法完成。

\n\n

至于对齐,如果ConstructedType大小只有 1 个字节,则需要为其添加对齐,以确保它仅在偶数字节上,否则 Rust 可能会选择将它们打包得更紧密:

\n\n
#[align(2)]\nstruct ConstructedType<\'ts> { \n    // ...\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

#[align(2)]如果大小大于 2 个字节,绝对不要添加。也许其他人可以提供使该部分更加健壮的建议。

\n