Rust: Fix Copy and Clone impls for a few generic types (#5577)
authorMathias Svensson <freaken@freaken.dk>
Mon, 28 Oct 2019 04:20:29 +0000 (05:20 +0100)
committerRobert Winslow <rw@users.noreply.github.com>
Mon, 28 Oct 2019 04:20:29 +0000 (00:20 -0400)
* 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
rust/flatbuffers/src/vector.rs
tests/rust_usage_test/Cargo.toml
tests/rust_usage_test/tests/integration_test.rs

index ccab938..06a22ea 100644 (file)
@@ -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<T>(UOffsetT, PhantomData<T>);
 
+// 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<T>` can always be copied, no matter that `T` you
+// have.
+impl<T> Copy for WIPOffset<T> {}
+impl<T> Clone for WIPOffset<T> {
+    #[inline(always)]
+    fn clone(&self) -> Self {
+        *self
+    }
+}
+
 impl<T> PartialEq for WIPOffset<T> {
     fn eq(&self, o: &WIPOffset<T>) -> bool {
         self.value() == o.value()
@@ -108,12 +120,12 @@ impl<'a, T: 'a> WIPOffset<T> {
     /// 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<UnionWIPOffset> {
+    pub fn as_union_value(self) -> WIPOffset<UnionWIPOffset> {
         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<T> Push for ForwardsUOffset<T> {
 
 /// 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<T>(UOffsetT, PhantomData<T>);
+
+// 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<T>` can always be copied, no matter that `T` you
+// have.
+impl<T> Copy for ForwardsUOffset<T> {}
+impl<T> Clone for ForwardsUOffset<T> {
+    #[inline(always)]
+    fn clone(&self) -> Self {
+        *self
+    }
+}
+
 impl<T> ForwardsUOffset<T> {
     #[inline(always)]
-    pub fn value(&self) -> UOffsetT {
+    pub fn value(self) -> UOffsetT {
         self.0
     }
 }
index de97abb..ef1986a 100644 (file)
@@ -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<T>);
 
+// 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 {
index 490d6d2..6178849 100644 (file)
@@ -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
index 0dace96..c2af738 100644 (file)
@@ -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<u32>: Copy, Clone);
+        static_assertions::assert_impl_all!(flatbuffers::WIPOffset<Vec<u32>>: Copy, Clone);
+
+        static_assertions::assert_impl_all!(flatbuffers::ForwardsUOffset<u32>: Copy, Clone);
+        static_assertions::assert_impl_all!(flatbuffers::ForwardsUOffset<Vec<u32>>: Copy, Clone);
+
+        static_assertions::assert_impl_all!(flatbuffers::Vector<'static, u32>: Copy, Clone);
+        static_assertions::assert_impl_all!(flatbuffers::Vector<'static, Vec<u32>>: 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.