Skip to content
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

cxx: implement slice support for nostd #1123

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
27 changes: 20 additions & 7 deletions build.rs
Expand Up @@ -3,13 +3,26 @@ use std::path::Path;
use std::process::Command;

fn main() {
cc::Build::new()
.file("src/cxx.cc")
.cpp(true)
.cpp_link_stdlib(None) // linked via link-cplusplus crate
.flag_if_supported(cxxbridge_flags::STD)
.warnings_into_errors(cfg!(deny_warnings))
.compile("cxxbridge1");
// Building without alloc, for a nostd target.
if !cfg!(feature = "alloc") {
cc::Build::new()
.file("src/cxx.cc")
.cpp(true)
.cpp_link_stdlib(None) // linked via link-cplusplus crate
.flag_if_supported(cxxbridge_flags::STD)
.warnings_into_errors(cfg!(deny_warnings))
.define("CXXBRIDGE1_RUST_STD", None) // Exclude all dependencies on std
.compile("cxxbridge1");
} else {
// Building for STD with all features
cc::Build::new()
.file("src/cxx.cc")
.cpp(true)
.cpp_link_stdlib(None) // linked via link-cplusplus crate
.flag_if_supported(cxxbridge_flags::STD)
.warnings_into_errors(cfg!(deny_warnings))
.compile("cxxbridge1");
}

println!("cargo:rerun-if-changed=src/cxx.cc");
println!("cargo:rerun-if-changed=include/cxx.h");
Expand Down
2 changes: 2 additions & 0 deletions gen/build/Cargo.toml
Expand Up @@ -13,9 +13,11 @@ repository = "https://github.com/dtolnay/cxx"
rust-version = "1.48"

[features]
default = ["std"]
parallel = ["cc/parallel"]
# incomplete features that are not covered by a compatibility guarantee:
experimental-async-fn = []
std = []

[dependencies]
cc = "1.0.49"
Expand Down
27 changes: 22 additions & 5 deletions gen/build/src/lib.rs
Expand Up @@ -385,12 +385,29 @@ fn make_include_dir(prj: &Project) -> Result<PathBuf> {
let include_dir = prj.out_dir.join("cxxbridge").join("include");
let cxx_h = include_dir.join("rust").join("cxx.h");
let ref shared_cxx_h = prj.shared_dir.join("rust").join("cxx.h");
if let Some(ref original) = env::var_os("DEP_CXXBRIDGE1_HEADER") {
out::symlink_file(original, cxx_h)?;
out::symlink_file(original, shared_cxx_h)?;
} else {
out::write(shared_cxx_h, gen::include::HEADER.as_bytes())?;

if !cfg!(feature = "std") {
// For a nonstd target, specify `#define CXXBRIDGE1_RUST_STD` to a copy of "include/cxx.h" and
// don't create a symlink to the original header (which has all std features enabled).
// This copy can now be included by a C++ file
// compiled/linked with `-nostdlib`
let mut new = "// Allow building for a nostd target by excluding std dependencies\n#define CXXBRIDGE1_RUST_STD\n"
.to_string()
.as_bytes()
.to_vec();
let mut byte_vec = gen::include::HEADER.as_bytes().to_vec();
new.append(&mut byte_vec);
let slice: &[u8] = &new;
out::write(shared_cxx_h, slice)?;
out::symlink_file(shared_cxx_h, cxx_h)?;
} else {
if let Some(ref original) = env::var_os("DEP_CXXBRIDGE1_HEADER") {
out::symlink_file(original, cxx_h)?;
out::symlink_file(original, shared_cxx_h)?;
} else {
out::write(shared_cxx_h, gen::include::HEADER.as_bytes())?;
out::symlink_file(shared_cxx_h, cxx_h)?;
}
}
Ok(include_dir)
}
Expand Down
24 changes: 17 additions & 7 deletions include/cxx.h
@@ -1,19 +1,22 @@
#pragma once
#include <algorithm>
#include <array>
#include <cassert>
#include <cstddef>
#include <cstdint>
#include <exception>
#include <initializer_list>
#include <stdexcept>
#include <string>

#ifndef CXXBRIDGE1_RUST_STD
#include <algorithm>
#include <cassert>
#include <exception>
#include <iosfwd>
#include <iterator>
#include <new>
#include <stdexcept>
#include <string>
#include <type_traits>
#include <utility>
#include <vector>
#endif // CXXBRIDGE1_RUST_STD
#if defined(_WIN32)
#include <basetsd.h>
#else
Expand All @@ -30,6 +33,7 @@ template <typename T>
class impl;
}

#ifndef CXXBRIDGE1_RUST_STD
#ifndef CXXBRIDGE1_RUST_STRING
#define CXXBRIDGE1_RUST_STRING
// https://cxx.rs/binding/string.html
Expand Down Expand Up @@ -151,6 +155,7 @@ class Str final {
std::array<std::uintptr_t, 2> repr;
};
#endif // CXXBRIDGE1_RUST_STR
#endif

#ifndef CXXBRIDGE1_RUST_SLICE
namespace detail {
Expand Down Expand Up @@ -412,8 +417,10 @@ using isize = ssize_t;
#endif
#endif // CXXBRIDGE1_RUST_ISIZE

#ifndef CXXBRIDGE1_RUST_STD
std::ostream &operator<<(std::ostream &, const String &);
std::ostream &operator<<(std::ostream &, const Str &);
#endif

#ifndef CXXBRIDGE1_RUST_OPAQUE
#define CXXBRIDGE1_RUST_OPAQUE
Expand Down Expand Up @@ -465,14 +472,17 @@ using f32 = float;
using f64 = double;

// Snake case aliases for use in code that uses this style for type names.
using string = String;
using str = Str;
template <typename T>
using slice = Slice<T>;
#ifndef CXXBRIDGE1_RUST_STD
using string = String;
using str = Str;
template <typename T>
using box = Box<T>;
template <typename T>
using vec = Vec<T>;
#endif

using error = Error;
template <typename Signature>
using fn = Fn<Signature>;
Expand Down
29 changes: 22 additions & 7 deletions src/cxx.cc
@@ -1,9 +1,12 @@
#include "../include/cxx.h"
#include <cstring>
#ifndef CXXBRIDGE1_RUST_STD
#include <iostream>
#include <memory>
#endif

extern "C" {
#ifndef CXXBRIDGE1_RUST_STD
void cxxbridge1$cxx_string$init(std::string *s, const std::uint8_t *ptr,
std::size_t len) noexcept {
new (s) std::string(reinterpret_cast<const char *>(ptr), len);
Expand Down Expand Up @@ -62,6 +65,7 @@ bool cxxbridge1$str$from(rust::Str *self, const char *ptr,
std::size_t len) noexcept;
const char *cxxbridge1$str$ptr(const rust::Str *self) noexcept;
std::size_t cxxbridge1$str$len(const rust::Str *self) noexcept;
#endif

// rust::Slice
void cxxbridge1$slice$new(void *self, const void *ptr,
Expand All @@ -73,6 +77,13 @@ std::size_t cxxbridge1$slice$len(const void *self) noexcept;
namespace rust {
inline namespace cxxbridge1 {

template <typename T>
static bool is_aligned(const void *ptr) noexcept {
auto iptr = reinterpret_cast<std::uintptr_t>(ptr);
return !(iptr % alignof(T));
}

#ifndef CXXBRIDGE1_RUST_STD
template <typename Exception>
void panic [[noreturn]] (const char *msg) {
#if defined(RUST_CXX_NO_EXCEPTIONS)
Expand All @@ -85,12 +96,6 @@ void panic [[noreturn]] (const char *msg) {

template void panic<std::out_of_range> [[noreturn]] (const char *msg);

template <typename T>
static bool is_aligned(const void *ptr) noexcept {
auto iptr = reinterpret_cast<std::uintptr_t>(ptr);
return !(iptr % alignof(T));
}

String::String() noexcept { cxxbridge1$string$new(this); }

String::String(const String &other) noexcept {
Expand Down Expand Up @@ -377,6 +382,7 @@ std::ostream &operator<<(std::ostream &os, const Str &s) {
os.write(s.data(), s.size());
return os;
}
#endif

void sliceInit(void *self, const void *ptr, std::size_t len) noexcept {
cxxbridge1$slice$new(self, ptr, len);
Expand Down Expand Up @@ -406,11 +412,13 @@ static_assert(sizeof(rust::isize) == sizeof(std::intptr_t),
static_assert(alignof(rust::isize) == alignof(std::intptr_t),
"unsupported ssize_t alignment");

#ifndef CXXBRIDGE1_RUST_STD
static_assert(std::is_trivially_copy_constructible<Str>::value,
"trivial Str(const Str &)");
static_assert(std::is_trivially_copy_assignable<Str>::value,
"trivial operator=(const Str &)");
static_assert(std::is_trivially_destructible<Str>::value, "trivial ~Str()");
#endif

static_assert(
std::is_trivially_copy_constructible<Slice<const std::uint8_t>>::value,
Expand Down Expand Up @@ -448,6 +456,7 @@ static_assert(!std::is_same<Vec<std::uint8_t>::const_iterator,
Vec<std::uint8_t>::iterator>::value,
"Vec<T>::const_iterator != Vec<T>::iterator");

#ifndef CXXBRIDGE1_RUST_STD
static const char *errorCopy(const char *ptr, std::size_t len) {
char *copy = new char[len];
std::memcpy(copy, ptr, len);
Expand Down Expand Up @@ -494,6 +503,7 @@ Error &Error::operator=(Error &&other) &noexcept {
other.len = 0;
return *this;
}
#endif

const char *Error::what() const noexcept { return this->msg; }

Expand All @@ -513,9 +523,11 @@ struct PtrLen final {
};
} // namespace repr

#ifndef CXXBRIDGE1_RUST_STD
extern "C" {
repr::PtrLen cxxbridge1$exception(const char *, std::size_t len) noexcept;
}
#endif

namespace detail {
// On some platforms size_t is the same C++ type as one of the sized integer
Expand All @@ -530,7 +542,7 @@ using isize_if_unique =
typename std::conditional<std::is_same<rust::isize, int64_t>::value ||
std::is_same<rust::isize, int32_t>::value,
struct isize_ignore, rust::isize>::type;

#ifndef CXXBRIDGE1_RUST_STD
class Fail final {
repr::PtrLen &throw$;

Expand All @@ -547,6 +559,7 @@ void Fail::operator()(const char *catch$) noexcept {
void Fail::operator()(const std::string &catch$) noexcept {
throw$ = cxxbridge1$exception(catch$.data(), catch$.length());
}
#endif
} // namespace detail

} // namespace cxxbridge1
Expand All @@ -559,6 +572,7 @@ void destroy(T *ptr) {
}
} // namespace

#ifndef CXXBRIDGE1_RUST_STD
extern "C" {
void cxxbridge1$unique_ptr$std$string$null(
std::unique_ptr<std::string> *ptr) noexcept {
Expand Down Expand Up @@ -790,3 +804,4 @@ inline namespace cxxbridge1 {
FOR_EACH_RUST_VEC(RUST_VEC_OPS)
} // namespace cxxbridge1
} // namespace rust
#endif // CXXBRIDGE1_RUST_STD