Skip to content

Use an outparameter to return values from closures #22

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Sep 24, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
154 changes: 101 additions & 53 deletions cpp_build/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,11 @@ extern crate lazy_static;

use std::env;
use std::path::{Path, PathBuf};
use std::fs::{remove_dir_all, create_dir, File};
use std::fs::{create_dir, remove_dir_all, File};
use std::io::prelude::*;
use syn::visit::Visitor;
use syn::{Mac, Span, Spanned, DUMMY_SPAN};
use cpp_common::{parsing, Closure, ClosureSig, Capture, Macro, LIB_NAME, STRUCT_METADATA_MAGIC,
use cpp_common::{parsing, Capture, Closure, ClosureSig, Macro, LIB_NAME, STRUCT_METADATA_MAGIC,
VERSION};
use cpp_synmap::SourceMap;

Expand All @@ -42,7 +42,8 @@ macro_rules! warnln {
const INTERNAL_CPP_STRUCTS: &'static str = r#"
/* THIS FILE IS GENERATED BY rust-cpp. DO NOT EDIT */

#include "stdint.h"
#include "stdint.h" // For {u}intN_t
#include <new> // For placement new

"#;

Expand All @@ -55,6 +56,13 @@ The OUT_DIR environment variable was not set.
NOTE: rust-cpp's build function must be run in a build script."#));

static ref CPP_DIR: PathBuf = OUT_DIR.join("rust_cpp");

static ref CARGO_MANIFEST_DIR: PathBuf =
PathBuf::from(env::var("CARGO_MANIFEST_DIR").expect(r#"
-- rust-cpp fatal error --

The CARGO_MANIFEST_DIR environment variable was not set.
NOTE: rust-cpp's build function must be run in a build script."#));
}

fn gen_cpp_lib(visitor: &Handle) -> PathBuf {
Expand All @@ -68,28 +76,28 @@ fn gen_cpp_lib(visitor: &Handle) -> PathBuf {
let mut sizealign = vec![];
for &Closure { ref body, ref sig } in &visitor.closures {
let &ClosureSig {
ref captures,
ref cpp,
..
} = sig;
ref captures,
ref cpp,
..
} = sig;

let hash = sig.name_hash();
let name = sig.extern_name();

let is_void = cpp == "void";

// Generate the sizes array with the sizes of each of the argument types
if cpp != "void" {
if is_void {
sizealign.push(format!(
"{{{hash}ull, 0, 1}}",
hash = hash
));
} else {
sizealign.push(format!("{{
{hash}ull,
sizeof({type}),
rustcpp::AlignOf<{type}>::value
}}", hash=hash, type=cpp));
} else {
sizealign.push(format!("{{
{hash}ull,
0,
1
}}",
hash = hash));
}
for &Capture { ref cpp, .. } in captures {
sizealign.push(format!("{{
Expand All @@ -102,40 +110,71 @@ fn gen_cpp_lib(visitor: &Handle) -> PathBuf {
// Generate the parameters and function declaration
let params = captures
.iter()
.map(|&Capture {
mutable,
ref name,
ref cpp,
}| if mutable {
format!("{} & {}", cpp, name)
} else {
format!("{} const& {}", cpp, name)
})
.map(
|&Capture {
mutable,
ref name,
ref cpp,
}| if mutable {
format!("{} & {}", cpp, name)
} else {
format!("{} const& {}", cpp, name)
},
)
.collect::<Vec<_>>()
.join(", ");

write!(output,
r#"
if is_void {
write!(
output,
r#"
extern "C" {{
{} {}({}) {{
{}
void {name}({params}) {{
{body}
}}
}}
"#,
name = &name,
params = params,
body = body.node
).unwrap();
} else {
let comma = if params.is_empty() { "" } else { "," };
let args = captures
.iter()
.map(|&Capture { ref name, .. }| name.as_ref())
.collect::<Vec<_>>()
.join(", ");
write!(
output,
r#"
static inline {ty} {name}_impl({params}) {{
{body}
}}
extern "C" {{
void {name}({params}{comma} void* __result) {{
::new(__result) ({ty})({name}_impl({args}));
}}
}}
"#,
cpp,
&name,
params,
body.node)
.unwrap();
name = &name,
params = params,
comma = comma,
ty = cpp,
args = args,
body = body.node
).unwrap();
}
}

let mut magic = vec![];
for mag in STRUCT_METADATA_MAGIC.iter() {
magic.push(format!("{}", mag));
}

write!(output,
r#"
write!(
output,
r#"

namespace rustcpp {{

Expand Down Expand Up @@ -170,27 +209,31 @@ MetaData metadata = {{

}} // namespace rustcpp
"#,
data = sizealign.join(", "),
length = sizealign.len(),
magic = magic.join(", "),
version = VERSION)
.unwrap();
data = sizealign.join(", "),
length = sizealign.len(),
magic = magic.join(", "),
version = VERSION
).unwrap();

result_path
}

fn clean_artifacts() {
if CPP_DIR.is_dir() {
remove_dir_all(&*CPP_DIR).expect(r#"
remove_dir_all(&*CPP_DIR).expect(
r#"
-- rust-cpp fatal error --

Failed to remove existing build artifacts from output directory."#);
Failed to remove existing build artifacts from output directory."#,
);
}

create_dir(&*CPP_DIR).expect(r#"
create_dir(&*CPP_DIR).expect(
r#"
-- rust-cpp fatal error --

Failed to create output object directory."#);
Failed to create output object directory."#,
);
}

/// This struct is for advanced users of the build script. It allows providing
Expand All @@ -200,18 +243,19 @@ Failed to create output object directory."#);
///
/// Internally, `cpp` uses `gcc-rs` to build the compilation artifact, and many
/// of the methods defined on this type directly proxy to an internal
/// `gcc::Config` object.
/// `gcc::Build` object.
pub struct Config {
gcc: gcc::Config,
gcc: gcc::Build,
}

impl Config {
/// Create a new `Config` object. This object will hold the configuration
/// options which control the build. If you don't need to make any changes,
/// `cpp_build::build` is a wrapper function around this interface.
pub fn new() -> Config {
let mut gcc = gcc::Config::new();
let mut gcc = gcc::Build::new();
gcc.cpp(true);
gcc.include(&*CARGO_MANIFEST_DIR);
Config { gcc: gcc }
}

Expand Down Expand Up @@ -396,9 +440,11 @@ impl Config {
/// reasons, but that usually won't do what you want. Use a different
/// `Config` object each time you want to build a crate.
pub fn build<P: AsRef<Path>>(&mut self, crate_root: P) {
assert_eq!(env!("CARGO_PKG_VERSION"),
VERSION,
"Internal Error: mismatched cpp_common and cpp_build versions");
assert_eq!(
env!("CARGO_PKG_VERSION"),
VERSION,
"Internal Error: mismatched cpp_common and cpp_build versions"
);

// Clean up any leftover artifacts
clean_artifacts();
Expand All @@ -408,15 +454,17 @@ impl Config {
let krate = match sm.add_crate_root(crate_root) {
Ok(krate) => krate,
Err(err) => {
warnln!(r#"-- rust-cpp parse error --
warnln!(
r#"-- rust-cpp parse error --

There was an error parsing the crate for the rust-cpp build script:

{}

In order to provide a better error message, the build script will exit
successfully, such that rustc can provide an error message."#,
err);
err
);
return;
}
};
Expand Down Expand Up @@ -449,7 +497,7 @@ struct Handle<'a> {
sm: &'a SourceMap,
}

fn extract_with_span(mut spanned: &mut Spanned<String>, src: &str, offset: usize, sm: &SourceMap) {
fn extract_with_span(spanned: &mut Spanned<String>, src: &str, offset: usize, sm: &SourceMap) {
if spanned.span != DUMMY_SPAN {
let src_slice = &src[spanned.span.lo..spanned.span.hi];
spanned.span.lo += offset;
Expand Down
8 changes: 4 additions & 4 deletions cpp_common/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ extern crate quote;
use std::collections::hash_map::DefaultHasher;
use std::hash::{Hash, Hasher};

use syn::{Ident, Ty, Spanned};
use syn::{Ident, Spanned, Ty};

pub const VERSION: &'static str = env!("CARGO_PKG_VERSION");

Expand Down Expand Up @@ -77,9 +77,9 @@ pub enum Macro {
}

pub mod parsing {
use syn::parse::{ident, string, ty, tt};
use syn::{Ty, Spanned, DUMMY_SPAN};
use super::{Capture, ClosureSig, Closure, Macro};
use syn::parse::{ident, string, tt, ty};
use syn::{Spanned, Ty, DUMMY_SPAN};
use super::{Capture, Closure, ClosureSig, Macro};

macro_rules! mac_body {
($i: expr, $submac:ident!( $($args:tt)* )) => {
Expand Down
Loading