From 4f3d9c452c2b3770aad7ec67fa9e63e35b726e8f Mon Sep 17 00:00:00 2001 From: Richard Berry Date: Wed, 20 Mar 2019 19:48:39 +0000 Subject: [PATCH 1/2] [Rust] flatc build script wrapper Co-authored-by: Geordon Worley --- .gitignore | 1 + rust/flatc/Cargo.toml | 14 + rust/flatc/build.rs | 63 ++++ rust/flatc/src/lib.rs | 279 ++++++++++++++++ tests/RustTest.sh | 20 ++ .../languages/Dockerfile.testing.rust.1_40_0 | 3 + .../Dockerfile.testing.rust.big_endian.1_40_0 | 2 + tests/include_test/include_test1_generated.rs | 102 ------ .../sub/include_test2_generated.rs | 298 ------------------ tests/rust_usage_test/Cargo.toml | 6 + .../bin/flexbuffers_alloc_check.rs | 2 +- tests/rust_usage_test/bin/monster_example.rs | 15 +- tests/rust_usage_test/build.rs | 31 ++ .../tests/build_script_test.rs | 27 ++ 14 files changed, 456 insertions(+), 407 deletions(-) create mode 100644 rust/flatc/Cargo.toml create mode 100644 rust/flatc/build.rs create mode 100644 rust/flatc/src/lib.rs delete mode 100644 tests/include_test/include_test1_generated.rs delete mode 100644 tests/include_test/sub/include_test2_generated.rs create mode 100644 tests/rust_usage_test/build.rs create mode 100644 tests/rust_usage_test/tests/build_script_test.rs diff --git a/.gitignore b/.gitignore index b783d0a8a1c..88e74c21517 100644 --- a/.gitignore +++ b/.gitignore @@ -120,6 +120,7 @@ dart/pubspec.lock dart/.dart_tool/ dart/build/ dart/doc/api/ +!rust/flatc Cargo.lock .corpus** .seed** diff --git a/rust/flatc/Cargo.toml b/rust/flatc/Cargo.toml new file mode 100644 index 00000000000..0ee3775d7a3 --- /dev/null +++ b/rust/flatc/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "flatc" +version = "0.1.0" +authors = ["Richard Berry ", "FlatBuffers Maintainers"] +license = "Apache-2.0" +build = "build.rs" +description = "Companion package to flatbuffers to generate code at compile time." +homepage = "https://google.github.io/flatbuffers/" +repository = "https://github.com/google/flatbuffers" +keywords = ["flatbuffers", "serialization", "zero-copy"] +categories = ["encoding", "data-structures", "memory-management"] + +[build-dependencies] +cmake = "0.1" diff --git a/rust/flatc/build.rs b/rust/flatc/build.rs new file mode 100644 index 00000000000..841d962d557 --- /dev/null +++ b/rust/flatc/build.rs @@ -0,0 +1,63 @@ +/* + * Copyright 2018 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +extern crate cmake; + +use std::{env, fs, path::Path, process::Command}; + +fn main() { + let git_sha = if let Ok(output) = Command::new("git") + .args(&["rev-parse", "--short=7", "HEAD"]) + .output() + { + String::from_utf8(output.stdout).expect("utf8 sha") + } else { + "unavailable".to_owned() + }; + + println!("cargo:rustc-env=FLATBUFFERS_COMMIT_SHA={}", git_sha.trim()); + + if let Ok(output) = Command::new("cmake").arg("--version").output() { + println!("\n\n{:?}\n\n", output); + } + + let flatc_root = Path::new(&env::var("CARGO_MANIFEST_DIR").unwrap()) + .join("..") + .join(".."); + + // CI workaround + let cmake_cache = flatc_root.join("CMakeCache.txt"); + if cmake_cache.exists() { + fs::remove_file(cmake_cache).expect("remove cmake cache"); + } + + let mut cmake = ::cmake::Config::new(flatc_root); + + cmake.define("CMAKE_BUILD_TYPE", "Release"); + cmake.define("CMAKE_INSTALL_BINDIR", "bin"); + cmake.define("FLATBUFFERS_BUILD_TESTS", "OFF"); + cmake.define("FLATBUFFERS_BUILD_FLATLIB", "OFF"); + cmake.define("FLATBUFFERS_BUILD_FLATHASH", "OFF"); + #[cfg(windows)] + cmake.cxxflag("/EHsc"); + + #[cfg(windows)] + let _ = if let Ok(cmake_vs_version) = env::var("CMAKE_VS_VERSION") { + cmake.generator(format!("Visual Studio {}", cmake_vs_version)); + }; + + cmake.build(); +} diff --git a/rust/flatc/src/lib.rs b/rust/flatc/src/lib.rs new file mode 100644 index 00000000000..2600e75a706 --- /dev/null +++ b/rust/flatc/src/lib.rs @@ -0,0 +1,279 @@ +/* + * Copyright 2018 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +//! # flatc +//! +//! Companion package to [`flatbuffers`] to generate code using `flatc` (the +//! FlatBuffers schema compiler) at compile time. +//! +//! This library is intended to be used as a `build-dependencies` entry in +//! `Cargo.toml`: +//! +//! ```toml +//! [dependencies] +//! flatbuffers = "0.5" +//! +//! [build-dependencies] +//! flatc = "0.1" +//! ``` +//! +//! # Examples +//! +//! Use the `Build` structure to compile schema files: +//! +//! ```no_run +//! extern crate flatc; +//! +//! fn main() { +//! flatc::Build::new() +//! .schema("schema/foo.fbs") +//! .compile(); +//! } +//! ``` +//! +//! Include the generated Rust code: +//! +//! ```ignore +//! mod foo_generated { +//! include!(concat!(env!("OUT_DIR"), "/foo_generated.rs")); +//! } +//! ``` +//! +//! [`flatbuffers`]: https://docs.rs/flatbuffers/latest + +#![cfg_attr(feature = "cargo-clippy", allow(new_without_default_derive))] + +use std::{env, fmt, io, iter::once, process::Command, path::{Path, PathBuf}}; + +/// The commit SHA of [google/flatbuffers.git] that the crate-supplied copy of +/// `flatc` was compiled with. +/// +/// [google/flatbuffers.git]: https://github.com/google/flatbuffers +const FLATBUFFERS_COMMIT_SHA: &str = env!("FLATBUFFERS_COMMIT_SHA"); + +/// The location of the copy of the `flatc` executable compiled by this crate. +const FLATC_EXECUTABLE: &str = concat!(env!("OUT_DIR"), "/bin/flatc"); + +/// An internal error that occured. +struct Error { + /// The kind of error. + kind: ErrorKind, + /// A helpful message. + message: String, +} + +impl Error { + /// Create a new instance of an `Error`. + fn new>(kind: ErrorKind, message: S) -> Self { + Self { + kind, + message: message.as_ref().to_owned(), + } + } +} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self.kind { + ErrorKind::IO => { + writeln!( + f, + "An I/O error occured during FlatBuffers compilation: {}\n", + self.message, + )?; + } + ErrorKind::FlatC => { + writeln!( + f, +"A flatc error occurred during schema compilation with the crate-supplied executable\n", + )?; + } + } + + writeln!(f, "Error message: {}", self.message)?; + writeln!(f, "flatc executable: {}", FLATC_EXECUTABLE)?; + writeln!(f, "flatbuffers commit: {}", FLATBUFFERS_COMMIT_SHA)?; + + Ok(()) + } +} + +impl From for Error { + fn from(error: io::Error) -> Self { + Self::new(ErrorKind::IO, format!("{}", error)) + } +} + +/// The type of errors that can occur when using `flatc`. +enum ErrorKind { + /// An I/O error occured. + IO, + /// An error occurred while using the schema compiler. + FlatC, +} + +/// A builder for compilation of one or multiple FlatBuffers schemas. +/// +/// This is the core type of `flatc`. For further documentation, see the +/// individual methods for this structure. +pub struct Build { + /// The path that compiled schema files will be written into. + output_path: Option, + /// The paths that will be tried in `include` statements in schemas. + include_paths: Vec, + /// The schema files that will be compiled. + schema: Vec, +} + +impl Build { + /// Create a new instance of a `flatc` compilation with no configuration. + /// + /// This is finished with the [`compile`](struct.Build.html#method.compile) + /// function. + pub fn new() -> Self { + Self { + output_path: None, + include_paths: Vec::new(), + schema: Vec::new(), + } + } + + /// Add a schema file to the files which will be compiled. + /// + /// ## Shell Command + /// + /// ```text + /// $ flatc -r foo.fbs bar.fbs baz.fbs + /// ``` + /// + /// ## Rust Equivalent + /// + /// ```no_run + /// extern crate flatc; + /// + /// fn main() { + /// flatc::Build::new() + /// .schema("foo.fbs") + /// .schema("bar.fbs") + /// .schema("baz.fbs") + /// .compile(); + /// } + /// ``` + pub fn schema>(&mut self, file: P) -> &mut Self { + self.schema.push(file.as_ref().to_path_buf()); + self + } + + /// Add include directories to the flatc compilation. + /// + /// The order in which directories are added will be preserved. + /// + /// ## Shell Command + /// + /// ```text + /// $ flatc -r -I dir1 -I dir2 foo.fbs + /// ``` + /// + /// ## Rust equivalent + /// + /// ```no_run + /// extern crate flatc; + /// + /// fn main() { + /// flatc::Build::new() + /// .schema("foo.fbs") + /// .include("dir1") + /// .include("dir2") + /// .compile(); + /// } + /// ``` + pub fn include>(&mut self, dir: P) -> &mut Self { + self.include_paths.push(dir.as_ref().to_path_buf()); + self + } + + /// Run the FlatBuffer schema compiler, generating one file for each of the + /// schemas added to the `Build` with the + /// [`schema`](struct.Build.html#method.schema) method. + /// + /// Output filenames are postfixed with "*_generated*", and the extension is + /// set to "*.rs*". These files are placed in `OUT_DIR`. They can be + /// included in your crate using compile time macros. + /// + /// # Example + /// + /// For a compilation of `foo.fbs`, you would include it in your main crate + /// with: + /// + /// ```ignore + /// mod foo_generated { + /// include!(concat!(env!("OUT_DIR"), "/foo_generated.rs")); + /// } + /// ``` + /// + /// # Panics + /// + /// This function will panic if it encounters any error. This will be + /// emitted as a compilation error when compiling your crate. + pub fn compile(&self) { + if let Err(e) = self.try_compile() { + panic!("\n\n{}\n\n", e); + } + } +} + +impl Build { + fn try_compile(&self) -> Result<(), Error> { + let output_path = self.output_path.as_ref().map_or_else( + || env::var("OUT_DIR").unwrap(), + |path| format!("{}", path.display()), + ); + + let include_paths = self + .include_paths + .iter() + .flat_map(|path| once("-I".to_string()).chain(once(path.display().to_string()))); + + let fbs_files = self.schema.iter(); + + Command::new(FLATC_EXECUTABLE) + .current_dir(env::var("CARGO_MANIFEST_DIR").unwrap()) + .arg("-r") + .args(&["-o", &output_path]) + .args(include_paths) + .args(fbs_files) + .output() + .map_err(Error::from) + .and_then(|output| { + if output.status.success() { + Ok(()) + } else { + Err(Error::new( + ErrorKind::FlatC, + String::from_utf8(output.stdout).unwrap().trim(), + )) + } + }) + } +} + +impl Build { + #[doc(hidden)] + pub fn output>(&mut self, dir: P) -> &mut Self { + self.output_path = Some(dir.as_ref().to_path_buf()); + self + } +} diff --git a/tests/RustTest.sh b/tests/RustTest.sh index 71258c928bc..f135870e79a 100755 --- a/tests/RustTest.sh +++ b/tests/RustTest.sh @@ -32,8 +32,19 @@ function check_test_result() { } cd ./rust_usage_test +<<<<<<< HEAD cargo test $TARGET_FLAG -- --quiet check_test_result "Rust tests" +======= +cargo test $TARGET_FLAG -- --quiet --skip build_script_wrapper +TEST_RESULT=$? +if [[ $TEST_RESULT == 0 ]]; then + echo "OK: Rust tests passed." +else + echo "KO: Rust tests failed." + exit 1 +fi +>>>>>>> d9e935e4... [Rust] flatc build script wrapper cargo run $TARGET_FLAG --bin=flatbuffers_alloc_check @@ -46,6 +57,15 @@ rustup component add clippy cargo clippy $TARGET_FLAG check_test_result "No Cargo clippy lints test" +cargo test $TARGET_FLAG -- --quiet --test build_script_wrapper +TEST_RESULT=$? +if [[ $TEST_RESULT == 0 ]]; then + echo "OK: Rust flatc build script wrapper test passed." +else + echo "KO: Rust flatc build script wrapper test failed." + exit 1 +fi + cargo bench $TARGET_FLAG # This test is dependent on flatc. diff --git a/tests/docker/languages/Dockerfile.testing.rust.1_40_0 b/tests/docker/languages/Dockerfile.testing.rust.1_40_0 index 849ad76ad39..ee43c1966f3 100644 --- a/tests/docker/languages/Dockerfile.testing.rust.1_40_0 +++ b/tests/docker/languages/Dockerfile.testing.rust.1_40_0 @@ -1,4 +1,7 @@ FROM rust:1.40.0-slim-stretch as base +RUN apt -qq update -y && apt -qq install -y \ + build-essential \ + cmake WORKDIR /code ADD . . RUN cp flatc_debian_stretch flatc diff --git a/tests/docker/languages/Dockerfile.testing.rust.big_endian.1_40_0 b/tests/docker/languages/Dockerfile.testing.rust.big_endian.1_40_0 index 3abf8df1925..ba9463e7e90 100644 --- a/tests/docker/languages/Dockerfile.testing.rust.big_endian.1_40_0 +++ b/tests/docker/languages/Dockerfile.testing.rust.big_endian.1_40_0 @@ -1,5 +1,7 @@ FROM rust:1.40.0-slim-stretch as base RUN apt -qq update -y && apt -qq install -y \ + build-essential \ + cmake \ gcc-mips-linux-gnu \ libexpat1 \ libmagic1 \ diff --git a/tests/include_test/include_test1_generated.rs b/tests/include_test/include_test1_generated.rs deleted file mode 100644 index d7511f9e042..00000000000 --- a/tests/include_test/include_test1_generated.rs +++ /dev/null @@ -1,102 +0,0 @@ -// automatically generated by the FlatBuffers compiler, do not modify - - - -use crate::include_test2_generated::*; -use std::mem; -use std::cmp::Ordering; - -extern crate flatbuffers; -use self::flatbuffers::EndianScalar; - -pub enum TableAOffset {} -#[derive(Copy, Clone, PartialEq)] - -pub struct TableA<'a> { - pub _tab: flatbuffers::Table<'a>, -} - -impl<'a> flatbuffers::Follow<'a> for TableA<'a> { - type Inner = TableA<'a>; - #[inline] - fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { - Self { _tab: flatbuffers::Table { buf, loc } } - } -} - -impl<'a> TableA<'a> { - #[inline] - pub fn init_from_table(table: flatbuffers::Table<'a>) -> Self { - TableA { _tab: table } - } - #[allow(unused_mut)] - pub fn create<'bldr: 'args, 'args: 'mut_bldr, 'mut_bldr>( - _fbb: &'mut_bldr mut flatbuffers::FlatBufferBuilder<'bldr>, - args: &'args TableAArgs<'args>) -> flatbuffers::WIPOffset> { - let mut builder = TableABuilder::new(_fbb); - if let Some(x) = args.b { builder.add_b(x); } - builder.finish() - } - - pub const VT_B: flatbuffers::VOffsetT = 4; - - #[inline] - pub fn b(&self) -> Option> { - self._tab.get::>(TableA::VT_B, None) - } -} - -impl flatbuffers::Verifiable for TableA<'_> { - #[inline] - fn run_verifier( - v: &mut flatbuffers::Verifier, pos: usize - ) -> Result<(), flatbuffers::InvalidFlatbuffer> { - use self::flatbuffers::Verifiable; - v.visit_table(pos)? - .visit_field::>(&"b", Self::VT_B, false)? - .finish(); - Ok(()) - } -} -pub struct TableAArgs<'a> { - pub b: Option>>, -} -impl<'a> Default for TableAArgs<'a> { - #[inline] - fn default() -> Self { - TableAArgs { - b: None, - } - } -} -pub struct TableABuilder<'a: 'b, 'b> { - fbb_: &'b mut flatbuffers::FlatBufferBuilder<'a>, - start_: flatbuffers::WIPOffset, -} -impl<'a: 'b, 'b> TableABuilder<'a, 'b> { - #[inline] - pub fn add_b(&mut self, b: flatbuffers::WIPOffset>) { - self.fbb_.push_slot_always::>(TableA::VT_B, b); - } - #[inline] - pub fn new(_fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>) -> TableABuilder<'a, 'b> { - let start = _fbb.start_table(); - TableABuilder { - fbb_: _fbb, - start_: start, - } - } - #[inline] - pub fn finish(self) -> flatbuffers::WIPOffset> { - let o = self.fbb_.end_table(self.start_); - flatbuffers::WIPOffset::new(o.value()) - } -} - -impl std::fmt::Debug for TableA<'_> { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - let mut ds = f.debug_struct("TableA"); - ds.field("b", &self.b()); - ds.finish() - } -} diff --git a/tests/include_test/sub/include_test2_generated.rs b/tests/include_test/sub/include_test2_generated.rs deleted file mode 100644 index 787ec19f15d..00000000000 --- a/tests/include_test/sub/include_test2_generated.rs +++ /dev/null @@ -1,298 +0,0 @@ -// automatically generated by the FlatBuffers compiler, do not modify - - - -use crate::include_test1_generated::*; -use std::mem; -use std::cmp::Ordering; - -extern crate flatbuffers; -use self::flatbuffers::EndianScalar; - -#[allow(unused_imports, dead_code)] -pub mod my_game { - - use crate::include_test1_generated::*; - use std::mem; - use std::cmp::Ordering; - - extern crate flatbuffers; - use self::flatbuffers::EndianScalar; -#[allow(unused_imports, dead_code)] -pub mod other_name_space { - - use crate::include_test1_generated::*; - use std::mem; - use std::cmp::Ordering; - - extern crate flatbuffers; - use self::flatbuffers::EndianScalar; - -#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")] -pub const ENUM_MIN_FROM_INCLUDE: i64 = 0; -#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")] -pub const ENUM_MAX_FROM_INCLUDE: i64 = 0; -#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")] -#[allow(non_camel_case_types)] -pub const ENUM_VALUES_FROM_INCLUDE: [FromInclude; 1] = [ - FromInclude::IncludeVal, -]; - -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)] -#[repr(transparent)] -pub struct FromInclude(pub i64); -#[allow(non_upper_case_globals)] -impl FromInclude { - pub const IncludeVal: Self = Self(0); - - pub const ENUM_MIN: i64 = 0; - pub const ENUM_MAX: i64 = 0; - pub const ENUM_VALUES: &'static [Self] = &[ - Self::IncludeVal, - ]; - /// Returns the variant's name or "" if unknown. - pub fn variant_name(self) -> Option<&'static str> { - match self { - Self::IncludeVal => Some("IncludeVal"), - _ => None, - } - } -} -impl std::fmt::Debug for FromInclude { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - if let Some(name) = self.variant_name() { - f.write_str(name) - } else { - f.write_fmt(format_args!("", self.0)) - } - } -} -impl<'a> flatbuffers::Follow<'a> for FromInclude { - type Inner = Self; - #[inline] - fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { - let b = flatbuffers::read_scalar_at::(buf, loc); - Self(b) - } -} - -impl flatbuffers::Push for FromInclude { - type Output = FromInclude; - #[inline] - fn push(&self, dst: &mut [u8], _rest: &[u8]) { - flatbuffers::emplace_scalar::(dst, self.0); - } -} - -impl flatbuffers::EndianScalar for FromInclude { - #[inline] - fn to_little_endian(self) -> Self { - let b = i64::to_le(self.0); - Self(b) - } - #[inline] - fn from_little_endian(self) -> Self { - let b = i64::from_le(self.0); - Self(b) - } -} - -impl<'a> flatbuffers::Verifiable for FromInclude { - #[inline] - fn run_verifier( - v: &mut flatbuffers::Verifier, pos: usize - ) -> Result<(), flatbuffers::InvalidFlatbuffer> { - use self::flatbuffers::Verifiable; - i64::run_verifier(v, pos) - } -} - -impl flatbuffers::SimpleToVerifyInSlice for FromInclude {} -// struct Unused, aligned to 4 -#[repr(transparent)] -#[derive(Clone, Copy, PartialEq, Default)] -pub struct Unused(pub [u8; 4]); -impl std::fmt::Debug for Unused { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - f.debug_struct("Unused") - .field("a", &self.a()) - .finish() - } -} - -impl flatbuffers::SimpleToVerifyInSlice for Unused {} -impl flatbuffers::SafeSliceAccess for Unused {} -impl<'a> flatbuffers::Follow<'a> for Unused { - type Inner = &'a Unused; - #[inline] - fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { - <&'a Unused>::follow(buf, loc) - } -} -impl<'a> flatbuffers::Follow<'a> for &'a Unused { - type Inner = &'a Unused; - #[inline] - fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { - flatbuffers::follow_cast_ref::(buf, loc) - } -} -impl<'b> flatbuffers::Push for Unused { - type Output = Unused; - #[inline] - fn push(&self, dst: &mut [u8], _rest: &[u8]) { - let src = unsafe { - ::std::slice::from_raw_parts(self as *const Unused as *const u8, Self::size()) - }; - dst.copy_from_slice(src); - } -} -impl<'b> flatbuffers::Push for &'b Unused { - type Output = Unused; - - #[inline] - fn push(&self, dst: &mut [u8], _rest: &[u8]) { - let src = unsafe { - ::std::slice::from_raw_parts(*self as *const Unused as *const u8, Self::size()) - }; - dst.copy_from_slice(src); - } -} - -impl<'a> flatbuffers::Verifiable for Unused { - #[inline] - fn run_verifier( - v: &mut flatbuffers::Verifier, pos: usize - ) -> Result<(), flatbuffers::InvalidFlatbuffer> { - use self::flatbuffers::Verifiable; - v.in_buffer::(pos) - } -} -impl Unused { - #[allow(clippy::too_many_arguments)] - pub fn new( - a: i32, - ) -> Self { - let mut s = Self([0; 4]); - s.set_a(a); - s - } - - pub fn a(&self) -> i32 { - let mut mem = core::mem::MaybeUninit::::uninit(); - unsafe { - core::ptr::copy_nonoverlapping( - self.0[0..].as_ptr(), - mem.as_mut_ptr() as *mut u8, - core::mem::size_of::(), - ); - mem.assume_init() - }.from_little_endian() - } - - pub fn set_a(&mut self, x: i32) { - let x_le = x.to_little_endian(); - unsafe { - core::ptr::copy_nonoverlapping( - &x_le as *const i32 as *const u8, - self.0[0..].as_mut_ptr(), - core::mem::size_of::(), - ); - } - } - -} - -pub enum TableBOffset {} -#[derive(Copy, Clone, PartialEq)] - -pub struct TableB<'a> { - pub _tab: flatbuffers::Table<'a>, -} - -impl<'a> flatbuffers::Follow<'a> for TableB<'a> { - type Inner = TableB<'a>; - #[inline] - fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { - Self { _tab: flatbuffers::Table { buf, loc } } - } -} - -impl<'a> TableB<'a> { - #[inline] - pub fn init_from_table(table: flatbuffers::Table<'a>) -> Self { - TableB { _tab: table } - } - #[allow(unused_mut)] - pub fn create<'bldr: 'args, 'args: 'mut_bldr, 'mut_bldr>( - _fbb: &'mut_bldr mut flatbuffers::FlatBufferBuilder<'bldr>, - args: &'args TableBArgs<'args>) -> flatbuffers::WIPOffset> { - let mut builder = TableBBuilder::new(_fbb); - if let Some(x) = args.a { builder.add_a(x); } - builder.finish() - } - - pub const VT_A: flatbuffers::VOffsetT = 4; - - #[inline] - pub fn a(&self) -> Option> { - self._tab.get::>(TableB::VT_A, None) - } -} - -impl flatbuffers::Verifiable for TableB<'_> { - #[inline] - fn run_verifier( - v: &mut flatbuffers::Verifier, pos: usize - ) -> Result<(), flatbuffers::InvalidFlatbuffer> { - use self::flatbuffers::Verifiable; - v.visit_table(pos)? - .visit_field::>(&"a", Self::VT_A, false)? - .finish(); - Ok(()) - } -} -pub struct TableBArgs<'a> { - pub a: Option>>, -} -impl<'a> Default for TableBArgs<'a> { - #[inline] - fn default() -> Self { - TableBArgs { - a: None, - } - } -} -pub struct TableBBuilder<'a: 'b, 'b> { - fbb_: &'b mut flatbuffers::FlatBufferBuilder<'a>, - start_: flatbuffers::WIPOffset, -} -impl<'a: 'b, 'b> TableBBuilder<'a, 'b> { - #[inline] - pub fn add_a(&mut self, a: flatbuffers::WIPOffset>) { - self.fbb_.push_slot_always::>(TableB::VT_A, a); - } - #[inline] - pub fn new(_fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>) -> TableBBuilder<'a, 'b> { - let start = _fbb.start_table(); - TableBBuilder { - fbb_: _fbb, - start_: start, - } - } - #[inline] - pub fn finish(self) -> flatbuffers::WIPOffset> { - let o = self.fbb_.end_table(self.start_); - flatbuffers::WIPOffset::new(o.value()) - } -} - -impl std::fmt::Debug for TableB<'_> { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - let mut ds = f.debug_struct("TableB"); - ds.field("a", &self.a()); - ds.finish() - } -} -} // pub mod OtherNameSpace -} // pub mod MyGame - diff --git a/tests/rust_usage_test/Cargo.toml b/tests/rust_usage_test/Cargo.toml index 45ecca66e28..ec5f5365267 100644 --- a/tests/rust_usage_test/Cargo.toml +++ b/tests/rust_usage_test/Cargo.toml @@ -4,6 +4,7 @@ version = "0.1.0" authors = ["Robert Winslow ", "Casper Neo ", "FlatBuffers Maintainers"] +build = "build.rs" [dependencies] flatbuffers = { path = "../../rust/flatbuffers" } @@ -43,6 +44,11 @@ bencher = "0.1.5" static_assertions = "1.0.0" rand = "*" quickcheck_derive = "*" +syn = { version = "0.15", features = ["full", "parsing"] } + +[build-dependencies] +flatc = { path = "../../rust/flatc" } +tempfile = "3.0" [[bench]] # setup for bencher diff --git a/tests/rust_usage_test/bin/flexbuffers_alloc_check.rs b/tests/rust_usage_test/bin/flexbuffers_alloc_check.rs index 847d7c6adcd..debd77ce437 100644 --- a/tests/rust_usage_test/bin/flexbuffers_alloc_check.rs +++ b/tests/rust_usage_test/bin/flexbuffers_alloc_check.rs @@ -137,4 +137,4 @@ fn main() { #[cfg(not(miri))] // slow. fn no_extra_allocations() { main() -} +} \ No newline at end of file diff --git a/tests/rust_usage_test/bin/monster_example.rs b/tests/rust_usage_test/bin/monster_example.rs index 2e3c7ac6065..033b9f9e855 100644 --- a/tests/rust_usage_test/bin/monster_example.rs +++ b/tests/rust_usage_test/bin/monster_example.rs @@ -1,16 +1,19 @@ extern crate flatbuffers; #[allow(dead_code, unused_imports)] -#[path = "../../include_test/include_test1_generated.rs"] -pub mod include_test1_generated; +pub mod include_test1_generated { + include!(concat!(env!("OUT_DIR"), "/include_test1_generated.rs")); +} #[allow(dead_code, unused_imports)] -#[path = "../../include_test/sub/include_test2_generated.rs"] -pub mod include_test2_generated; +pub mod include_test2_generated { + include!(concat!(env!("OUT_DIR"), "/include_test2_generated.rs")); +} #[allow(dead_code, unused_imports, clippy::approx_constant)] -#[path = "../../monster_test_generated.rs"] -mod monster_test_generated; +mod monster_test_generated { + include!(concat!(env!("OUT_DIR"), "/monster_test_generated.rs")); +} pub use monster_test_generated::my_game; use std::io::Read; diff --git a/tests/rust_usage_test/build.rs b/tests/rust_usage_test/build.rs new file mode 100644 index 00000000000..19c4fcdceb8 --- /dev/null +++ b/tests/rust_usage_test/build.rs @@ -0,0 +1,31 @@ +/* + * Copyright 2018 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +extern crate tempfile; + +use std::{env, fs}; + +fn main() { + flatc::Build::new() + .include("../include_test/") + .schema("../monster_test.fbs") + .schema("../include_test/include_test1.fbs") + .schema("../include_test/sub/include_test2.fbs") + .compile(); + + // `OUT_DIR` undefined during `cargo test` + println!("cargo:rustc-env=OUT_DIR={}", env::var("OUT_DIR").unwrap()); +} diff --git a/tests/rust_usage_test/tests/build_script_test.rs b/tests/rust_usage_test/tests/build_script_test.rs new file mode 100644 index 00000000000..5959206f3c3 --- /dev/null +++ b/tests/rust_usage_test/tests/build_script_test.rs @@ -0,0 +1,27 @@ +/* + * Copyright 2018 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +extern crate syn; + +use std::{env, fs, path::Path}; + +#[test] +fn build_script_wrapper() { + let output = Path::new(&env::var("OUT_DIR").unwrap()).join("monster_generated.rs"); + + let src = fs::read_to_string(&output).expect("Failed to read generated code"); + let _ = ::syn::parse_file(&src).expect("Invalid output generated"); +} From 96214d49c039af8b3a822d6dc8134823fd72816d Mon Sep 17 00:00:00 2001 From: Geordon Worley Date: Tue, 9 Feb 2021 12:21:48 -0500 Subject: [PATCH 2/2] add a method to support --gen-all flag --- rust/flatc/Cargo.toml | 1 + rust/flatc/build.rs | 4 +--- rust/flatc/src/lib.rs | 40 +++++++++++++++++++++++++++------- tests/rust_usage_test/build.rs | 2 +- 4 files changed, 35 insertions(+), 12 deletions(-) diff --git a/rust/flatc/Cargo.toml b/rust/flatc/Cargo.toml index 0ee3775d7a3..bf60802496a 100644 --- a/rust/flatc/Cargo.toml +++ b/rust/flatc/Cargo.toml @@ -1,6 +1,7 @@ [package] name = "flatc" version = "0.1.0" +edition = "2018" authors = ["Richard Berry ", "FlatBuffers Maintainers"] license = "Apache-2.0" build = "build.rs" diff --git a/rust/flatc/build.rs b/rust/flatc/build.rs index 841d962d557..d062d250d63 100644 --- a/rust/flatc/build.rs +++ b/rust/flatc/build.rs @@ -14,8 +14,6 @@ * limitations under the License. */ -extern crate cmake; - use std::{env, fs, path::Path, process::Command}; fn main() { @@ -52,7 +50,7 @@ fn main() { cmake.define("FLATBUFFERS_BUILD_FLATLIB", "OFF"); cmake.define("FLATBUFFERS_BUILD_FLATHASH", "OFF"); #[cfg(windows)] - cmake.cxxflag("/EHsc"); + cmake.cxxflag("/EHsc"); #[cfg(windows)] let _ = if let Ok(cmake_vs_version) = env::var("CMAKE_VS_VERSION") { diff --git a/rust/flatc/src/lib.rs b/rust/flatc/src/lib.rs index 2600e75a706..2bc3149e800 100644 --- a/rust/flatc/src/lib.rs +++ b/rust/flatc/src/lib.rs @@ -136,6 +136,8 @@ pub struct Build { include_paths: Vec, /// The schema files that will be compiled. schema: Vec, + /// Whether or not --gen-all is passed. + gen_all: bool, } impl Build { @@ -148,6 +150,7 @@ impl Build { output_path: None, include_paths: Vec::new(), schema: Vec::new(), + gen_all: false, } } @@ -205,6 +208,34 @@ impl Build { self } + /// This tells flatc to put all the code for includes into the same + /// generated file. This helps mitigate issue flatbuffers#5589. + /// It is set to `false` by default, but for Rust it is currently + /// necessary for significant usage of flatbuffers. + /// + /// ## Shell Command + /// + /// ```text + /// $ flatc -r --gen-all -I dir1 -I dir2 foo.fbs + /// ``` + /// + /// ## Rust equivalent + /// + /// ```no_run + /// fn main() { + /// flatc::Build::new() + /// .gen_all(true) + /// .schema("foo.fbs") + /// .include("dir1") + /// .include("dir2") + /// .compile(); + /// } + /// ``` + pub fn gen_all(&mut self, gen_all: bool) -> &mut Self { + self.gen_all = gen_all; + self + } + /// Run the FlatBuffer schema compiler, generating one file for each of the /// schemas added to the `Build` with the /// [`schema`](struct.Build.html#method.schema) method. @@ -252,6 +283,7 @@ impl Build { Command::new(FLATC_EXECUTABLE) .current_dir(env::var("CARGO_MANIFEST_DIR").unwrap()) .arg("-r") + .args(if self.gen_all { &["--gen-all"][..] } else { &[] }) .args(&["-o", &output_path]) .args(include_paths) .args(fbs_files) @@ -269,11 +301,3 @@ impl Build { }) } } - -impl Build { - #[doc(hidden)] - pub fn output>(&mut self, dir: P) -> &mut Self { - self.output_path = Some(dir.as_ref().to_path_buf()); - self - } -} diff --git a/tests/rust_usage_test/build.rs b/tests/rust_usage_test/build.rs index 19c4fcdceb8..e0898893133 100644 --- a/tests/rust_usage_test/build.rs +++ b/tests/rust_usage_test/build.rs @@ -16,7 +16,7 @@ extern crate tempfile; -use std::{env, fs}; +use std::env; fn main() { flatc::Build::new()