From b4774d2354425b29b233170cdef23c97c03d4aa8 Mon Sep 17 00:00:00 2001 From: Mathias Svensson Date: Mon, 28 Oct 2019 05:20:29 +0100 Subject: [PATCH] Rust: Fix Copy and Clone impls for a few generic types (#5577) * Rust: Fix Copy and Clone impls for a few generic types * Add tests for Copy+Clone * Wrap Copy+Clone checks in a #[test] function --- rust/flatbuffers/src/primitives.rs | 35 +++++++++++++++++++++---- rust/flatbuffers/src/vector.rs | 12 ++++++++- tests/rust_usage_test/Cargo.toml | 1 + tests/rust_usage_test/tests/integration_test.rs | 15 +++++++++++ 4 files changed, 57 insertions(+), 6 deletions(-) diff --git a/rust/flatbuffers/src/primitives.rs b/rust/flatbuffers/src/primitives.rs index ccab938..06a22ea 100644 --- a/rust/flatbuffers/src/primitives.rs +++ b/rust/flatbuffers/src/primitives.rs @@ -79,9 +79,21 @@ pub struct VTableWIPOffset {} /// data relative to the *end* of an in-progress FlatBuffer. The /// FlatBufferBuilder uses this to track the location of objects in an absolute /// way. The impl of Push converts a WIPOffset into a ForwardsUOffset. -#[derive(Debug, Clone, Copy)] +#[derive(Debug)] pub struct WIPOffset(UOffsetT, PhantomData); +// We cannot use derive for these two impls, as the derived impls would only +// implement `Copy` and `Clone` for `T: Copy` and `T: Clone` respectively. +// However `WIPOffset` can always be copied, no matter that `T` you +// have. +impl Copy for WIPOffset {} +impl Clone for WIPOffset { + #[inline(always)] + fn clone(&self) -> Self { + *self + } +} + impl PartialEq for WIPOffset { fn eq(&self, o: &WIPOffset) -> bool { self.value() == o.value() @@ -108,12 +120,12 @@ impl<'a, T: 'a> WIPOffset { /// Return a wrapped value that brings its meaning as a union WIPOffset /// into the type system. #[inline(always)] - pub fn as_union_value(&self) -> WIPOffset { + pub fn as_union_value(self) -> WIPOffset { WIPOffset::new(self.0) } /// Get the underlying value. #[inline(always)] - pub fn value(&self) -> UOffsetT { + pub fn value(self) -> UOffsetT { self.0 } } @@ -139,11 +151,24 @@ impl Push for ForwardsUOffset { /// ForwardsUOffset is used by Follow to traverse a FlatBuffer: the pointer /// is incremented by the value contained in this type. -#[derive(Debug, Clone, Copy)] +#[derive(Debug)] pub struct ForwardsUOffset(UOffsetT, PhantomData); + +// We cannot use derive for these two impls, as the derived impls would only +// implement `Copy` and `Clone` for `T: Copy` and `T: Clone` respectively. +// However `ForwardsUOffset` can always be copied, no matter that `T` you +// have. +impl Copy for ForwardsUOffset {} +impl Clone for ForwardsUOffset { + #[inline(always)] + fn clone(&self) -> Self { + *self + } +} + impl ForwardsUOffset { #[inline(always)] - pub fn value(&self) -> UOffsetT { + pub fn value(self) -> UOffsetT { self.0 } } diff --git a/rust/flatbuffers/src/vector.rs b/rust/flatbuffers/src/vector.rs index de97abb..ef1986a 100644 --- a/rust/flatbuffers/src/vector.rs +++ b/rust/flatbuffers/src/vector.rs @@ -25,9 +25,19 @@ use endian_scalar::{read_scalar, read_scalar_at}; use follow::Follow; use primitives::*; -#[derive(Debug, Clone, Copy)] +#[derive(Debug)] pub struct Vector<'a, T: 'a>(&'a [u8], usize, PhantomData); +// We cannot use derive for these two impls, as it would only implement Copy +// and Clone for `T: Copy` and `T: Clone` respectively. However `Vector<'a, T>` +// can always be copied, no matter that `T` you have. +impl<'a, T> Copy for Vector<'a, T> {} +impl<'a, T> Clone for Vector<'a, T> { + fn clone(&self) -> Self { + *self + } +} + impl<'a, T: 'a> Vector<'a, T> { #[inline(always)] pub fn new(buf: &'a [u8], loc: usize) -> Self { diff --git a/tests/rust_usage_test/Cargo.toml b/tests/rust_usage_test/Cargo.toml index 490d6d2..6178849 100644 --- a/tests/rust_usage_test/Cargo.toml +++ b/tests/rust_usage_test/Cargo.toml @@ -19,6 +19,7 @@ path = "bin/alloc_check.rs" quickcheck = "0.6" # TODO(rw): look into moving to criterion.rs bencher = "0.1.5" +static_assertions = "1.0.0" [[bench]] # setup for bencher diff --git a/tests/rust_usage_test/tests/integration_test.rs b/tests/rust_usage_test/tests/integration_test.rs index 0dace96..c2af738 100644 --- a/tests/rust_usage_test/tests/integration_test.rs +++ b/tests/rust_usage_test/tests/integration_test.rs @@ -2694,6 +2694,21 @@ mod byte_layouts { } } +#[cfg(test)] +mod copy_clone_traits { + #[test] + fn follow_types_implement_copy_and_clone() { + static_assertions::assert_impl_all!(flatbuffers::WIPOffset: Copy, Clone); + static_assertions::assert_impl_all!(flatbuffers::WIPOffset>: Copy, Clone); + + static_assertions::assert_impl_all!(flatbuffers::ForwardsUOffset: Copy, Clone); + static_assertions::assert_impl_all!(flatbuffers::ForwardsUOffset>: Copy, Clone); + + static_assertions::assert_impl_all!(flatbuffers::Vector<'static, u32>: Copy, Clone); + static_assertions::assert_impl_all!(flatbuffers::Vector<'static, Vec>: Copy, Clone); + } +} + // this is not technically a test, but we want to always keep this generated // file up-to-date, and the simplest way to do that is to make sure that when // tests are run, the file is generated. -- 2.7.4