wip new C++ library

This commit is contained in:
Caelan Sayler
2024-10-16 07:40:30 +01:00
committed by Caelan
parent e44a6d317e
commit ba04923fd0
29 changed files with 526 additions and 1567 deletions

1
.gitignore vendored
View File

@@ -11,6 +11,7 @@ cargo.log
cross.log
*.tgz
*.node
out/
#################
## Eclipse

87
Cargo.lock generated
View File

@@ -422,6 +422,16 @@ dependencies = [
"objc",
]
[[package]]
name = "codespan-reporting"
version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e"
dependencies = [
"termcolor",
"unicode-width",
]
[[package]]
name = "color_quant"
version = "1.1.0"
@@ -526,6 +536,50 @@ dependencies = [
"cfg-if 1.0.0",
]
[[package]]
name = "cxx"
version = "1.0.129"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cbdc8cca144dce1c4981b5c9ab748761619979e515c3d53b5df385c677d1d007"
dependencies = [
"cc",
"cxxbridge-flags",
"cxxbridge-macro",
"link-cplusplus",
]
[[package]]
name = "cxx-build"
version = "1.0.129"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c5764c3142ab44fcf857101d12c0ddf09c34499900557c764f5ad0597159d1fc"
dependencies = [
"cc",
"codespan-reporting",
"once_cell",
"proc-macro2",
"quote",
"scratch",
"syn 2.0.79",
]
[[package]]
name = "cxxbridge-flags"
version = "1.0.129"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d422aff542b4fa28c2ce8e5cc202d42dbf24702345c1fba3087b2d3f8a1b90ff"
[[package]]
name = "cxxbridge-macro"
version = "1.0.129"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1719100f31492cd6adeeab9a0f46cdbc846e615fdb66d7b398aa46ec7fdd06f"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.79",
]
[[package]]
name = "deranged"
version = "0.3.11"
@@ -1070,6 +1124,15 @@ dependencies = [
"libc",
]
[[package]]
name = "link-cplusplus"
version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9d240c6f7e1ba3a28b0249f774e6a9dd0175054b52dfbb61b16eb8505c3785c9"
dependencies = [
"cc",
]
[[package]]
name = "linux-raw-sys"
version = "0.4.14"
@@ -1649,6 +1712,12 @@ dependencies = [
"windows-sys 0.59.0",
]
[[package]]
name = "scratch"
version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a3cf7c11c38cb994f3d40e8a8cde3bbd1f72a435e4c49e85d6553d8312306152"
[[package]]
name = "security-framework"
version = "2.11.1"
@@ -2051,6 +2120,12 @@ dependencies = [
"tinyvec",
]
[[package]]
name = "unicode-width"
version = "0.1.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af"
[[package]]
name = "ureq"
version = "2.10.1"
@@ -2170,6 +2245,18 @@ dependencies = [
"winsafe",
]
[[package]]
name = "velopack_libc"
version = "0.0.0-local"
dependencies = [
"anyhow",
"cxx",
"cxx-build",
"lazy_static",
"log",
"velopack",
]
[[package]]
name = "velopack_nodeffi"
version = "0.0.0-local"

View File

@@ -4,10 +4,10 @@ members = [
"src/bins",
"src/lib-rust",
"src/lib-nodejs/velopack_nodeffi",
"src/lib-cpp",
]
exclude = [
"samples/RustIced",
"src/lib-cpp/generator"
]
[workspace.package]
@@ -23,6 +23,8 @@ edition = "2021"
rust-version = "1.75"
[workspace.dependencies]
cxx = "1.0"
cxx-build = "1.0"
velopack = { path = "src/lib-rust" }
log = "0.4"
native-tls = "0.2"

View File

@@ -1,47 +0,0 @@
cmake_minimum_required(VERSION 3.9 FATAL_ERROR)
project(velopack_cpp)
include(CheckIncludeFileCXX)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED True)
include_directories(${CMAKE_SOURCE_DIR}/api)
if(WIN32)
set(RUST_STATIC_LIB "velopack_cpp_bridge.lib")
link_libraries(ntdll)
foreach(flag_var
CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE
CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO)
if(${flag_var} MATCHES "/MD")
string(REGEX REPLACE "/MD" "/MT" ${flag_var} "${${flag_var}}")
endif()
endforeach()
elseif(UNIX AND NOT APPLE)
set(RUST_STATIC_LIB "velopack_cpp_bridge.a")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static-libgcc -static-libstdc++")
elseif(APPLE)
set(RUST_STATIC_LIB "velopack_cpp_bridge.a")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static-libstdc++ -static-libgcc")
endif()
# Full path for the library
set(RUST_STATIC_LIB_PATH "${CMAKE_SOURCE_DIR}/../../target/release/${RUST_STATIC_LIB}")
# Custom command to build the library
add_custom_command(OUTPUT ${RUST_STATIC_LIB_PATH}
COMMAND cargo build --release
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/generator
COMMENT "Running pre-build command")
# Custom target to handle the build of the library
add_custom_target(build_rust_lib DEPENDS ${RUST_STATIC_LIB_PATH})
# Main executable
add_executable(${PROJECT_NAME} main.cpp)
# Ensure the library is built before the main project
add_dependencies(${PROJECT_NAME} build_rust_lib)
# Link the library after it has been built
target_link_libraries(${PROJECT_NAME} ${RUST_STATIC_LIB_PATH})

28
src/lib-cpp/Cargo.toml Normal file
View File

@@ -0,0 +1,28 @@
[package]
name = "velopack_libc"
publish = false
version.workspace = true
authors.workspace = true
homepage.workspace = true
repository.workspace = true
documentation.workspace = true
keywords.workspace = true
categories.workspace = true
license.workspace = true
edition.workspace = true
rust-version.workspace = true
[lib]
path = "src/lib.rs"
crate-type = ["cdylib", "staticlib"]
[dependencies]
cxx.workspace = true
velopack.workspace = true
anyhow.workspace = true
lazy_static.workspace = true
log.workspace = true
[build-dependencies]
cxx-build.workspace = true

View File

@@ -1,108 +0,0 @@
// Automatically generated by flapigen
#pragma once
//for assert
#include <cassert>
//for std::abort
#include <cstdlib>
//for std::move
#include <utility>
//for std::conditional
#include <type_traits>
#include <stdint.h>
#include "c_Foo.h"
namespace velopack_cpp {
template<bool>
class FooWrapper;
using Foo = FooWrapper<true>;
using FooRef = FooWrapper<false>;
template<bool OWN_DATA>
class FooWrapper {
public:
using value_type = FooWrapper<true>;
friend class FooWrapper<true>;
friend class FooWrapper<false>;
using SelfType = typename std::conditional<OWN_DATA, FooOpaque *, const FooOpaque *>::type;
using CForeignType = FooOpaque;
FooWrapper(FooWrapper &&o) noexcept: self_(o.self_)
{
o.self_ = nullptr;
}
FooWrapper &operator=(FooWrapper &&o) noexcept
{
assert(this != &o);
free_mem(this->self_);
self_ = o.self_;
o.self_ = nullptr;
return *this;
}
explicit FooWrapper(SelfType o) noexcept: self_(o) {}
FooOpaque *release() noexcept
{
FooOpaque *ret = self_;
self_ = nullptr;
return ret;
}
explicit operator SelfType() const noexcept { return self_; }
FooWrapper<false> as_rref() const noexcept { return FooWrapper<false>{ self_ }; }
const FooWrapper<true> &as_cref() const noexcept { return reinterpret_cast<const FooWrapper<true> &>(*this); }
FooWrapper(const FooWrapper&) = delete;
FooWrapper &operator=(const FooWrapper&) = delete;
FooWrapper(int32_t val) noexcept
{
this->self_ = Foo_new(val);
if (this->self_ == nullptr) {
std::abort();
}
}
int32_t f(int32_t a, int32_t b) const noexcept;
//Custom doc comment
void setField(int32_t v) noexcept;
private:
static void free_mem(SelfType &p) noexcept
{
if (OWN_DATA && p != nullptr) {
Foo_delete(p);
}
p = nullptr;
}
public:
~FooWrapper() noexcept
{
free_mem(this->self_);
}
private:
SelfType self_;
};
template<bool OWN_DATA>
inline int32_t FooWrapper<OWN_DATA>::f(int32_t a, int32_t b) const noexcept
{
int32_t ret = Foo_f(this->self_, a, b);
return ret;
}
template<bool OWN_DATA>
inline void FooWrapper<OWN_DATA>::setField(int32_t v) noexcept
{
Foo_setField(this->self_, v);
}
} // namespace velopack_cpp

View File

@@ -1,9 +0,0 @@
// Automatically generated by flapigen
#pragma once
namespace velopack_cpp {
template<bool>
class FooWrapper;
using Foo = FooWrapper<true>;
using FooRef = FooWrapper<false>;
} // namespace velopack_cpp

View File

@@ -1,28 +0,0 @@
// Automatically generated by flapigen
#pragma once
//for (u)intX_t types
#include <stdint.h>
#ifdef __cplusplus
static_assert(sizeof(uintptr_t) == sizeof(uint8_t) * 8,
"our conversion usize <-> uintptr_t is wrong");
extern "C" {
#endif
typedef struct FooOpaque FooOpaque;
FooOpaque *Foo_new(int32_t val);
int32_t Foo_f(const FooOpaque * const self, int32_t a, int32_t b);
//Custom doc comment
void Foo_setField(FooOpaque * const self, int32_t v);
void Foo_delete(const FooOpaque *self);
#ifdef __cplusplus
}
#endif

View File

@@ -1,77 +0,0 @@
#pragma once
#include "rust_foreign_slice_iter.hpp"
namespace velopack_cpp {
template <class ForeignClassRef, typename CContainerType>
class RustForeignSlice final : public CContainerType {
public:
using const_reference = ForeignClassRef;
using CForeignType = typename ForeignClassRef::CForeignType;
using value_type = typename ForeignClassRef::value_type;
using iterator = RustForeignSliceIterator<ForeignClassRef>;
using const_iterator = RustForeignSliceIterator<ForeignClassRef>;
RustForeignSlice() noexcept { reset(); }
explicit RustForeignSlice(const CContainerType &o) noexcept
{
this->data = o.data;
this->len = o.len;
this->step = o.step;
}
RustForeignSlice(const RustForeignSlice &) = delete;
RustForeignSlice &operator=(const RustForeignSlice &) = delete;
RustForeignSlice(RustForeignSlice &&o) noexcept
{
this->data = o.data;
this->len = o.len;
this->step = o.step;
o.reset();
}
RustForeignSlice &operator=(RustForeignSlice &&o) noexcept
{
this->data = o.data;
this->len = o.len;
this->step = o.step;
o.reset();
return *this;
}
~RustForeignSlice() noexcept {}
size_t size() const noexcept { return this->len; }
bool empty() const noexcept { return this->len == 0; }
ForeignClassRef operator[](size_t i) const noexcept
{
assert(i < this->len);
auto p = static_cast<const uint8_t *>(this->data);
p += this->step * i;
auto elem_ptr = static_cast<const CForeignType *>(static_cast<const void *>(p));
return ForeignClassRef{ elem_ptr };
}
iterator begin() noexcept { return iterator{ this->data, this->step }; }
const_iterator begin() const noexcept { return const_iterator{ this->data, this->step }; }
iterator end() noexcept
{
auto p = static_cast<const uint8_t *>(this->data);
p += this->step * this->len;
return iterator{ p, this->step };
}
const_iterator end() const noexcept
{
auto p = static_cast<const uint8_t *>(this->data);
p += this->step * this->len;
return const_iterator{ p, this->step };
}
private:
void reset()
{
this->step = 0;
this->len = 0;
this->data = nullptr;
}
};
} // namespace velopack_cpp

View File

@@ -1,131 +0,0 @@
#pragma once
#include <cstddef> //ptrdiff_t
#include <cassert>
#include <iterator>
template <typename T> class RustForeignSliceIterator final {
public:
using iterator_category = std::random_access_iterator_tag;
using value_type = T;
using difference_type = std::ptrdiff_t;
using pointer = const T *;
using reference = T;
using CForeignType = typename T::CForeignType;
RustForeignSliceIterator() noexcept
: ptr(nullptr)
, step(0)
{
}
RustForeignSliceIterator(const void *p, size_t s) noexcept
: ptr(p)
, step(s)
{
}
/**
* \defgroup Forward iterator requirements
*/
/*@{*/
T operator*() const noexcept
{
auto elem_ptr = static_cast<const CForeignType *>(this->ptr);
return T{ elem_ptr };
}
RustForeignSliceIterator &operator++() noexcept
{
this->ptr = static_cast<const uint8_t *>(this->ptr) + this->step;
return *this;
}
/*@}*/
/**
* \defgroup Bidirectional iterator requirements
*/
/*@{*/
RustForeignSliceIterator &operator--() noexcept
{
this->ptr = static_cast<const uint8_t *>(this->ptr) - this->step;
return *this;
}
/*@}*/
/**
* \defgroup Random access iterator requirements
*/
/*@{*/
T operator[](ptrdiff_t n) const noexcept
{
auto p = static_cast<const uint8_t *>(this->ptr) + n * this->step;
auto elem_ptr = static_cast<const CForeignType *>(p);
return T{ elem_ptr };
}
RustForeignSliceIterator &operator+=(ptrdiff_t n) noexcept
{
this->ptr = static_cast<const uint8_t *>(this->ptr) + n * this->step;
return *this;
}
RustForeignSliceIterator operator+(ptrdiff_t n) const noexcept
{
const void *p = static_cast<const uint8_t *>(this->ptr) + n * this->step;
return RustForeignSliceIterator(p, this->step);
}
RustForeignSliceIterator &operator-=(ptrdiff_t n) noexcept
{
this->ptr = static_cast<const uint8_t *>(this->ptr) - n * this->step;
return *this;
}
RustForeignSliceIterator operator-(ptrdiff_t n) const noexcept
{
const void *p = static_cast<const uint8_t *>(this->ptr) - n * this->step;
return RustForeignSliceIterator(p, this->step);
}
ptrdiff_t operator-(const RustForeignSliceIterator &o) const noexcept
{
assert(this->step == o.step);
ptrdiff_t diff
= static_cast<const uint8_t *>(this->ptr) - static_cast<const uint8_t *>(o.ptr);
// if container empty step may be 0, to prevent div by 0
if (diff != 0) {
return diff / this->step;
}
else {
return 0;
}
}
bool operator<(const RustForeignSliceIterator &o) const noexcept
{
assert(this->step == o.step);
return this->ptr < o.ptr;
}
bool operator>(const RustForeignSliceIterator &o) const noexcept
{
assert(this->step == o.step);
return this->ptr > o.ptr;
}
bool operator<=(const RustForeignSliceIterator &o) const noexcept { return !operator>(o); }
bool operator>=(const RustForeignSliceIterator &o) const noexcept { return !operator<(o); }
/*@}*/
bool operator==(const RustForeignSliceIterator<T> &o) const noexcept
{
assert(this->step == o.step);
return this->ptr == o.ptr;
}
bool operator!=(const RustForeignSliceIterator<T> &o) const noexcept { return !operator==(o); }
private:
const void *ptr;
uintptr_t step;
};

View File

@@ -1,123 +0,0 @@
#pragma once
#include <cassert>
#include "rust_foreign_slice_impl.hpp"
#include "rust_foreign_slice_iter.hpp"
#include "rust_slice.h"
#include "rust_slice_mut.h"
namespace velopack_cpp {
template <class ForeignClassRef, typename CContainerType, void (*FreeFunc)(CContainerType),
void (*PushFunc)(CContainerType *, void *),
void *(*RemoveFunc)(CContainerType *, uintptr_t), const uintptr_t &ELEM_SIZE>
class RustForeignVec final : private CContainerType {
public:
using const_reference = ForeignClassRef;
using CForeignType = typename ForeignClassRef::CForeignType;
using value_type = typename ForeignClassRef::value_type;
using iterator = RustForeignSliceIterator<ForeignClassRef>;
using const_iterator = RustForeignSliceIterator<ForeignClassRef>;
RustForeignVec() noexcept { reset(*this); }
explicit RustForeignVec(const CContainerType &o) noexcept
{
this->data = o.data;
this->len = o.len;
this->capacity = o.capacity;
}
RustForeignVec(const RustForeignVec &) = delete;
RustForeignVec &operator=(const RustForeignVec &) = delete;
RustForeignVec(RustForeignVec &&o) noexcept
{
this->data = o.data;
this->len = o.len;
this->capacity = o.capacity;
reset(o);
}
RustForeignVec &operator=(RustForeignVec &&o) noexcept
{
free_mem();
this->data = o.data;
this->len = o.len;
this->capacity = o.capacity;
reset(o);
return *this;
}
~RustForeignVec() noexcept { free_mem(); }
size_t size() const noexcept { return this->len; }
bool empty() const noexcept { return this->len == 0; }
ForeignClassRef operator[](size_t i) const noexcept
{
assert(i < this->len);
auto p = static_cast<const uint8_t *>(this->data);
p += ELEM_SIZE * i;
auto elem_ptr = static_cast<const CForeignType *>(static_cast<const void *>(p));
return ForeignClassRef{ elem_ptr };
}
void push(value_type o) noexcept { PushFunc(this, o.release()); }
value_type remove(size_t idx) noexcept
{
auto p = static_cast<CForeignType *>(RemoveFunc(this, idx));
return value_type{ p };
}
iterator begin() noexcept { return iterator{ this->data, ELEM_SIZE }; }
const_iterator begin() const noexcept { return const_iterator{ this->data, ELEM_SIZE }; }
iterator end() noexcept
{
auto p = static_cast<const uint8_t *>(this->data);
p += ELEM_SIZE * this->len;
return iterator{ p, ELEM_SIZE };
}
const_iterator end() const noexcept
{
auto p = static_cast<const uint8_t *>(this->data);
p += ELEM_SIZE * this->len;
return const_iterator{ p, ELEM_SIZE };
}
RustForeignSlice<ForeignClassRef, CRustObjectSlice> as_slice() const noexcept
{
return RustForeignSlice<ForeignClassRef, CRustObjectSlice>{ CRustObjectSlice{
this->data, this->len, ELEM_SIZE } };
}
RustForeignSlice<ForeignClassRef, CRustObjectMutSlice> as_slice_mut() noexcept
{
return RustForeignSlice<ForeignClassRef, CRustObjectMutSlice>{ CRustObjectMutSlice{
this->data, this->len, ELEM_SIZE } };
}
void clear() noexcept { free_mem(); }
CContainerType release() noexcept
{
CContainerType ret{ this->data, this->len, this->capacity };
reset(*this);
return ret;
}
private:
void free_mem() noexcept
{
FreeFunc(*this);
reset(*this);
}
static void reset(RustForeignVec &o) noexcept
{
// Rust Vec::new uses NonNull::danling with similar value
o.data = reinterpret_cast<value_type *>(std::alignment_of<value_type>::value);
o.len = 0;
o.capacity = 0;
}
};
} // namespace velopack_cpp

View File

@@ -1,46 +0,0 @@
// Automatically generated by flapigen
#pragma once
//for (u)intX_t types
#include <stdint.h>
#ifdef __cplusplus
static_assert(sizeof(uintptr_t) == sizeof(uint8_t) * 8,
"our conversion usize <-> uintptr_t is wrong");
#endif
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
struct CRustObjectSlice {
/*const*/void * data;
uintptr_t len;
uintptr_t step;
};
#ifdef __cplusplus
} // extern "C" {
#endif
#ifdef __cplusplus
#include "rust_foreign_slice_impl.hpp"
namespace velopack_cpp {
template<typename T>
using RustForeignSliceConst = RustForeignSlice<T, CRustObjectSlice>;
}
#endif
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
struct CRustSliceAccess {
/*const*/void * data;
uintptr_t len;
};
#ifdef __cplusplus
} // extern "C" {
#endif

View File

@@ -1,50 +0,0 @@
#pragma once
#include <cstdint>
#include <cstddef>
#include "rust_slice.h"
namespace velopack_cpp {
template <typename IndexAccess> class RustSliceAccess final : public CRustSliceAccess {
public:
using ReturnType = typename IndexAccess::ReturnType;
RustSliceAccess() noexcept { reset(); }
explicit RustSliceAccess(CRustSliceAccess o) noexcept
{
this->data = o.data;
this->len = o.len;
}
RustSliceAccess(const RustSliceAccess &) = delete;
RustSliceAccess &operator=(const RustSliceAccess &) = delete;
RustSliceAccess(RustSliceAccess &&o) noexcept
{
this->data = o.data;
this->len = o.len;
o.reset();
}
RustSliceAccess &operator=(RustSliceAccess &&o) noexcept
{
this->data = o.data;
this->len = o.len;
o.reset();
return *this;
}
~RustSliceAccess() noexcept {}
size_t size() const noexcept { return this->len; }
bool empty() const noexcept { return this->len == 0; }
ReturnType operator[](size_t i) const noexcept
{
assert(i < this->len);
return IndexAccess::index(*this, i);
}
private:
void reset() noexcept
{
this->data = nullptr;
this->len = 0;
}
};
} // namespace velopack_cpp

View File

@@ -1,33 +0,0 @@
// Automatically generated by flapigen
#pragma once
//for (u)intX_t types
#include <stdint.h>
#ifdef __cplusplus
static_assert(sizeof(uintptr_t) == sizeof(uint8_t) * 8,
"our conversion usize <-> uintptr_t is wrong");
#endif
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
struct CRustObjectMutSlice {
void * data;
uintptr_t len;
uintptr_t step;
};
#ifdef __cplusplus
} // extern "C" {
#endif
#ifdef __cplusplus
#include "rust_foreign_slice_impl.hpp"
namespace velopack_cpp {
template<typename T>
using RustForeignSliceMut = RustForeignSlice<T, CRustObjectMutSlice>;
}
#endif

View File

@@ -1,59 +0,0 @@
#pragma once
#include <cstdint>
#include <type_traits>
namespace velopack_cpp {
template <typename value_type> class RustSlice final {
public:
using iterator = value_type *;
using const_iterator = const value_type *;
explicit RustSlice(value_type *p, size_t n) noexcept
{
this->data = p;
this->len = n;
}
RustSlice(const RustSlice &) = delete;
RustSlice &operator=(const RustSlice &) = delete;
RustSlice(RustSlice &&o) noexcept
{
this->data = o.data;
this->len = o.len;
reset(o);
}
RustSlice &operator=(RustSlice &&o) noexcept
{
this->data = o.data;
this->len = o.len;
reset(o);
return *this;
}
size_t size() const noexcept { return this->len; }
bool empty() const noexcept { return this->len == 0; }
const value_type &operator[](size_t i) const noexcept { return this->data[i]; }
value_type &operator[](size_t i) noexcept { return this->data[i]; }
iterator begin() noexcept { return this->data; }
const_iterator begin() const noexcept { return this->data; }
iterator end() noexcept { return this->data + this->len; }
const_iterator end() const noexcept { return this->data + this->len; }
template <typename CContainerType> CContainerType as_c() const noexcept
{
return CContainerType{ this->data, this->len };
}
private:
value_type *data;
uintptr_t len;
static void reset(RustSlice &o) noexcept
{
o.data = nullptr;
o.len = 0;
}
};
} // namespace velopack_cpp

View File

@@ -1,127 +0,0 @@
// Automatically generated by flapigen
#pragma once
//for (u)intX_t types
#include <stdint.h>
#ifdef __cplusplus
static_assert(sizeof(uintptr_t) == sizeof(uint8_t) * 8,
"our conversion usize <-> uintptr_t is wrong");
#endif
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
struct CRustStrView {
const char * data;
uintptr_t len;
};
#ifdef __cplusplus
} // extern "C" {
#endif
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
struct CRustString {
const char * data;
uintptr_t len;
uintptr_t capacity;
};
#ifdef __cplusplus
} // extern "C" {
#endif
#ifdef __cplusplus
extern "C" {
#endif
void crust_string_free(struct CRustString x);
#ifdef __cplusplus
} // extern "C" {
#endif
#ifdef __cplusplus
extern "C" {
#endif
struct CRustString crust_string_clone(struct CRustString x);
#ifdef __cplusplus
} // extern "C" {
#endif
#ifdef __cplusplus
#include <string>
#include <string_view>
namespace velopack_cpp {
class RustString final : private CRustString {
public:
explicit RustString(const CRustString &o) noexcept
{
data = o.data;
len = o.len;
capacity = o.capacity;
}
RustString() noexcept { reset(*this); }
RustString(const RustString &o) noexcept
: RustString(crust_string_clone(o))
{
}
RustString &operator=(const RustString &o) noexcept
{
if (this != &o) {
free_mem();
auto copy = crust_string_clone(o);
data = copy.data;
len = copy.len;
capacity = copy.capacity;
}
return *this;
}
RustString(RustString &&o) noexcept
{
data = o.data;
len = o.len;
capacity = o.capacity;
reset(o);
}
RustString &operator=(RustString &&o) noexcept
{
free_mem();
data = o.data;
len = o.len;
capacity = o.capacity;
reset(o);
return *this;
}
~RustString() noexcept { free_mem(); }
std::string to_std_string() const { return std::string(data, len); }
size_t size() const noexcept { return this->len; }
bool empty() const noexcept { return this->len == 0; }
std::string_view to_string_view() const { return std::string_view(data, len); }
private:
void free_mem() noexcept
{
if (data != nullptr) {
crust_string_free(*this);
reset(*this);
}
}
static void reset(RustString &o) noexcept
{
o.data = nullptr;
o.len = 0;
o.capacity = 0;
}
};
} // namespace velopack_cpp
#endif // __cplusplus

View File

@@ -1,38 +0,0 @@
// Automatically generated by flapigen
#pragma once
//for (u)intX_t types
#include <stdint.h>
#ifdef __cplusplus
static_assert(sizeof(uintptr_t) == sizeof(uint8_t) * 8,
"our conversion usize <-> uintptr_t is wrong");
#endif
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
struct CRustVecAccess {
/*const*/void * data;
uintptr_t len;
uintptr_t capacity;
};
#ifdef __cplusplus
} // extern "C" {
#endif
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
struct CRustForeignVec {
/*const*/void * data;
uintptr_t len;
uintptr_t capacity;
};
#ifdef __cplusplus
} // extern "C" {
#endif

View File

@@ -1,58 +0,0 @@
#pragma once
#include <cstddef>
namespace velopack_cpp {
template <typename VectorTrait, typename CContainerType>
class RustVecAccess final : private CContainerType {
public:
using ElemType = typename VectorTrait::ElemType;
explicit RustVecAccess(const CContainerType &o) noexcept
{
this->data = o.data;
this->len = o.len;
this->capacity = o.capacity;
}
RustVecAccess() noexcept { reset(*this); }
RustVecAccess(const RustVecAccess &) = delete;
RustVecAccess &operator=(const RustVecAccess &) = delete;
RustVecAccess(RustVecAccess &&o) noexcept
{
this->data = o.data;
this->len = o.len;
this->capacity = o.capacity;
reset(o);
}
RustVecAccess &operator=(RustVecAccess &&o) noexcept
{
free_mem();
this->data = o.data;
this->len = o.len;
this->capacity = o.capacity;
reset(o);
return *this;
}
~RustVecAccess() noexcept { free_mem(); }
size_t size() const noexcept { return this->len; }
bool empty() const noexcept { return this->len == 0; }
ElemType operator[](size_t i) const noexcept { return VectorTrait::index(*this, i); }
private:
void free_mem() noexcept
{
if (this->data != nullptr) {
VectorTrait::free(*this);
reset(*this);
}
}
static void reset(RustVecAccess &o) noexcept
{
o.data = nullptr;
o.len = 0;
o.capacity = 0;
}
};
} // namespace velopack_cpp

View File

@@ -1,78 +0,0 @@
#pragma once
#include <type_traits>
namespace velopack_cpp {
namespace internal {
template <typename T, typename E> E field_type(E T::*);
}
template <typename CContainerType, void (*FreeFunc)(CContainerType)>
class RustVec final : private CContainerType {
public:
using value_type =
typename std::remove_const<typename std::remove_reference<decltype(*internal::field_type(
&CContainerType::data))>::type>::type;
using iterator = value_type *;
using const_iterator = const value_type *;
explicit RustVec(const CContainerType &o) noexcept
{
this->data = o.data;
this->len = o.len;
this->capacity = o.capacity;
}
RustVec() noexcept { reset(*this); }
RustVec(const RustVec &) = delete;
RustVec &operator=(const RustVec &) = delete;
RustVec(RustVec &&o) noexcept
{
this->data = o.data;
this->len = o.len;
this->capacity = o.capacity;
reset(o);
}
RustVec &operator=(RustVec &&o) noexcept
{
free_mem();
this->data = o.data;
this->len = o.len;
this->capacity = o.capacity;
reset(o);
return *this;
}
~RustVec() noexcept { free_mem(); }
size_t size() const noexcept { return this->len; }
bool empty() const noexcept { return this->len == 0; }
const value_type &operator[](size_t i) const noexcept { return this->data[i]; }
iterator begin() noexcept { return this->data; }
const_iterator begin() const noexcept { return this->data; }
iterator end() noexcept { return this->data + this->len; }
const_iterator end() const noexcept { return this->data + this->len; }
void clear() noexcept { free_mem(); }
CContainerType release() noexcept
{
CContainerType ret{ this->data, this->len, this->capacity };
reset(*this);
return ret;
}
private:
void free_mem() noexcept
{
FreeFunc(*this);
reset(*this);
}
static void reset(RustVec &o) noexcept
{
// Rust Vec::new uses NonNull::danling with similar value
o.data = reinterpret_cast<value_type *>(std::alignment_of<value_type>::value);
o.len = 0;
o.capacity = 0;
}
};
} // namespace velopack_cpp

11
src/lib-cpp/build.rs Normal file
View File

@@ -0,0 +1,11 @@
fn main() {
cxx_build::bridge("src/lib.rs")
// .file("src/blobstore.cc")
.flag_if_supported("/std:c++17")
.std("c++17")
.compile("velopack_libc");
println!("cargo:rerun-if-changed=src/lib.rs");
println!("cargo:rerun-if-changed=include/Velopack.hpp");
println!("cargo:rerun-if-changed=include/bridge.hpp");
}

View File

@@ -1,18 +0,0 @@
[package]
name = "velopack_cpp_bridge"
version = "0.0.0-local"
edition = "2021"
[lib]
name = "velopack_cpp_bridge"
path = "src/lib.rs"
crate-type = ["cdylib", "staticlib"]
[dependencies]
rifgen = "*"
velopack = { path = "../../lib-rust" }
[build-dependencies]
flapigen = "*"
rifgen = "*"

View File

@@ -1,19 +0,0 @@
use flapigen::{CppConfig, CppOptional, CppStrView, CppVariant, LanguageConfig};
use std::{env, path::Path, process::Command};
fn main() {
use rifgen::{Generator, Language, TypeCases};
let source_folder = "./src";
let out_file = "./src/cpp_glue.rs.in";
Generator::new(TypeCases::CamelCase, Language::Cpp, source_folder).generate_interface(out_file);
let cpp_cfg = CppConfig::new(Path::new("..").join("api"), "velopack_cpp".into())
.cpp_optional(CppOptional::Std17)
.cpp_variant(CppVariant::Std17)
.cpp_str_view(CppStrView::Std17);
let swig_gen = flapigen::Generator::new(LanguageConfig::CppConfig(cpp_cfg));
swig_gen.expand("velopack_cpp", Path::new("./src/cpp_glue.rs.in"), &Path::new("src").join("cpp_glue.rs"));
Command::new("rustfmt").arg("src/cpp_glue.rs").status().unwrap();
}

View File

@@ -1,440 +0,0 @@
#[allow(unused_macros)]
macro_rules! swig_c_str {
($ lit : expr) => {
concat!($lit, "\0").as_ptr() as *const ::std::os::raw::c_char
};
}
#[allow(dead_code)]
pub trait SwigForeignClass {
fn c_class_name() -> *const ::std::os::raw::c_char;
fn box_object(x: Self) -> *mut ::std::os::raw::c_void;
fn unbox_object(p: *mut ::std::os::raw::c_void) -> Self;
}
#[allow(dead_code)]
pub trait SwigForeignEnum {
fn as_u32(&self) -> u32;
fn from_u32(_: u32) -> Self;
}
#[allow(dead_code)]
#[doc = ""]
trait SwigFrom<T> {
fn swig_from(_: T) -> Self;
}
#[allow(dead_code)]
#[repr(C)]
#[derive(Clone, Copy)]
pub struct CRustStrView {
data: *const ::std::os::raw::c_char,
len: usize,
}
#[allow(dead_code)]
impl CRustStrView {
fn from_str(s: &str) -> CRustStrView {
CRustStrView { data: s.as_ptr() as *const ::std::os::raw::c_char, len: s.len() }
}
}
#[allow(dead_code)]
#[repr(C)]
#[derive(Copy, Clone)]
pub struct CRustString {
data: *const ::std::os::raw::c_char,
len: usize,
capacity: usize,
}
#[allow(dead_code)]
impl CRustString {
pub fn from_string(s: String) -> CRustString {
let data = s.as_ptr() as *const ::std::os::raw::c_char;
let len = s.len();
let capacity = s.capacity();
::std::mem::forget(s);
CRustString { data, len, capacity }
}
}
#[allow(dead_code)]
#[repr(C)]
#[derive(Clone, Copy)]
pub struct CRustObjectSlice {
data: *const ::std::os::raw::c_void,
len: usize,
step: usize,
}
#[allow(dead_code)]
#[repr(C)]
pub struct CRustObjectMutSlice {
data: *mut ::std::os::raw::c_void,
len: usize,
step: usize,
}
#[allow(dead_code)]
#[repr(C)]
#[derive(Clone, Copy)]
pub struct CRustSliceAccess {
data: *const ::std::os::raw::c_void,
len: usize,
}
#[allow(dead_code)]
impl CRustSliceAccess {
pub fn from_slice<T>(sl: &[T]) -> Self {
Self { data: sl.as_ptr() as *const ::std::os::raw::c_void, len: sl.len() }
}
}
#[allow(dead_code)]
#[repr(C)]
#[derive(Copy, Clone)]
pub struct CRustVecAccess {
data: *const ::std::os::raw::c_void,
len: usize,
capacity: usize,
}
#[allow(dead_code)]
impl CRustVecAccess {
pub fn from_vec<T>(mut v: Vec<T>) -> Self {
let data = v.as_mut_ptr() as *const ::std::os::raw::c_void;
let len = v.len();
let capacity = v.capacity();
::std::mem::forget(v);
Self { data, len, capacity }
}
pub fn to_slice<'a, T>(cs: Self) -> &'a [T] {
unsafe { ::std::slice::from_raw_parts(cs.data as *const T, cs.len) }
}
pub fn to_vec<T>(cs: Self) -> Vec<T> {
unsafe { Vec::from_raw_parts(cs.data as *mut T, cs.len, cs.capacity) }
}
}
#[allow(dead_code)]
#[repr(C)]
#[derive(Copy, Clone)]
pub struct CRustForeignVec {
data: *const ::std::os::raw::c_void,
len: usize,
capacity: usize,
}
#[allow(dead_code)]
impl CRustForeignVec {
pub fn from_vec<T: SwigForeignClass>(mut v: Vec<T>) -> CRustForeignVec {
let data = v.as_mut_ptr() as *const ::std::os::raw::c_void;
let len = v.len();
let capacity = v.capacity();
::std::mem::forget(v);
CRustForeignVec { data, len, capacity }
}
}
#[allow(dead_code)]
#[inline]
fn push_foreign_class_to_vec<T: SwigForeignClass>(vec: *mut CRustForeignVec, elem: *mut ::std::os::raw::c_void) {
assert!(!vec.is_null());
let vec: &mut CRustForeignVec = unsafe { &mut *vec };
let mut v = unsafe { Vec::from_raw_parts(vec.data as *mut T, vec.len, vec.capacity) };
v.push(T::unbox_object(elem));
vec.data = v.as_mut_ptr() as *const ::std::os::raw::c_void;
vec.len = v.len();
vec.capacity = v.capacity();
::std::mem::forget(v);
}
#[allow(dead_code)]
#[inline]
fn remove_foreign_class_from_vec<T: SwigForeignClass>(vec: *mut CRustForeignVec, index: usize) -> *mut ::std::os::raw::c_void {
assert!(!vec.is_null());
let vec: &mut CRustForeignVec = unsafe { &mut *vec };
let mut v = unsafe { Vec::from_raw_parts(vec.data as *mut T, vec.len, vec.capacity) };
let elem: T = v.remove(index);
vec.data = v.as_mut_ptr() as *const ::std::os::raw::c_void;
vec.len = v.len();
vec.capacity = v.capacity();
::std::mem::forget(v);
T::box_object(elem)
}
#[allow(dead_code)]
#[inline]
fn drop_foreign_class_vec<T: SwigForeignClass>(v: CRustForeignVec) {
let v = unsafe { Vec::from_raw_parts(v.data as *mut T, v.len, v.capacity) };
drop(v);
}
use crate::*;
#[allow(non_snake_case)]
#[test]
fn test_CRustStrView_layout() {
#[repr(C)]
struct MyCRustStrView {
data: *const ::std::os::raw::c_char,
len: usize,
}
assert_eq!(::std::mem::size_of::<MyCRustStrView>(), ::std::mem::size_of::<CRustStrView>());
assert_eq!(::std::mem::align_of::<MyCRustStrView>(), ::std::mem::align_of::<CRustStrView>());
let our_s: MyCRustStrView = unsafe { ::std::mem::zeroed() };
let user_s: CRustStrView = unsafe { ::std::mem::zeroed() };
#[allow(dead_code)]
fn check_CRustStrView_data_type_fn(s: &CRustStrView) -> &*const ::std::os::raw::c_char {
&s.data
}
let offset_our = ((&our_s.data as *const *const ::std::os::raw::c_char) as usize) - ((&our_s as *const MyCRustStrView) as usize);
let offset_user = ((&user_s.data as *const *const ::std::os::raw::c_char) as usize) - ((&user_s as *const CRustStrView) as usize);
assert_eq!(offset_our, offset_user);
#[allow(dead_code)]
fn check_CRustStrView_len_type_fn(s: &CRustStrView) -> &usize {
&s.len
}
let offset_our = ((&our_s.len as *const usize) as usize) - ((&our_s as *const MyCRustStrView) as usize);
let offset_user = ((&user_s.len as *const usize) as usize) - ((&user_s as *const CRustStrView) as usize);
assert_eq!(offset_our, offset_user);
}
#[allow(non_snake_case)]
#[test]
fn test_CRustString_layout() {
#[repr(C)]
struct MyCRustString {
data: *const ::std::os::raw::c_char,
len: usize,
capacity: usize,
}
assert_eq!(::std::mem::size_of::<MyCRustString>(), ::std::mem::size_of::<CRustString>());
assert_eq!(::std::mem::align_of::<MyCRustString>(), ::std::mem::align_of::<CRustString>());
let our_s: MyCRustString = unsafe { ::std::mem::zeroed() };
let user_s: CRustString = unsafe { ::std::mem::zeroed() };
#[allow(dead_code)]
fn check_CRustString_data_type_fn(s: &CRustString) -> &*const ::std::os::raw::c_char {
&s.data
}
let offset_our = ((&our_s.data as *const *const ::std::os::raw::c_char) as usize) - ((&our_s as *const MyCRustString) as usize);
let offset_user = ((&user_s.data as *const *const ::std::os::raw::c_char) as usize) - ((&user_s as *const CRustString) as usize);
assert_eq!(offset_our, offset_user);
#[allow(dead_code)]
fn check_CRustString_len_type_fn(s: &CRustString) -> &usize {
&s.len
}
let offset_our = ((&our_s.len as *const usize) as usize) - ((&our_s as *const MyCRustString) as usize);
let offset_user = ((&user_s.len as *const usize) as usize) - ((&user_s as *const CRustString) as usize);
assert_eq!(offset_our, offset_user);
#[allow(dead_code)]
fn check_CRustString_capacity_type_fn(s: &CRustString) -> &usize {
&s.capacity
}
let offset_our = ((&our_s.capacity as *const usize) as usize) - ((&our_s as *const MyCRustString) as usize);
let offset_user = ((&user_s.capacity as *const usize) as usize) - ((&user_s as *const CRustString) as usize);
assert_eq!(offset_our, offset_user);
}
#[no_mangle]
pub extern "C" fn crust_string_free(x: CRustString) {
let s = unsafe { String::from_raw_parts(x.data as *mut u8, x.len, x.capacity) };
drop(s);
}
#[no_mangle]
pub extern "C" fn crust_string_clone(x: CRustString) -> CRustString {
let s = unsafe { String::from_raw_parts(x.data as *mut u8, x.len, x.capacity) };
let ret = CRustString::from_string(s.clone());
::std::mem::forget(s);
ret
}
#[allow(non_snake_case)]
#[test]
fn test_CRustObjectSlice_layout() {
#[repr(C)]
struct MyCRustObjectSlice {
data: *const ::std::os::raw::c_void,
len: usize,
step: usize,
}
assert_eq!(::std::mem::size_of::<MyCRustObjectSlice>(), ::std::mem::size_of::<CRustObjectSlice>());
assert_eq!(::std::mem::align_of::<MyCRustObjectSlice>(), ::std::mem::align_of::<CRustObjectSlice>());
let our_s: MyCRustObjectSlice = unsafe { ::std::mem::zeroed() };
let user_s: CRustObjectSlice = unsafe { ::std::mem::zeroed() };
#[allow(dead_code)]
fn check_CRustObjectSlice_data_type_fn(s: &CRustObjectSlice) -> &*const ::std::os::raw::c_void {
&s.data
}
let offset_our = ((&our_s.data as *const *const ::std::os::raw::c_void) as usize) - ((&our_s as *const MyCRustObjectSlice) as usize);
let offset_user = ((&user_s.data as *const *const ::std::os::raw::c_void) as usize) - ((&user_s as *const CRustObjectSlice) as usize);
assert_eq!(offset_our, offset_user);
#[allow(dead_code)]
fn check_CRustObjectSlice_len_type_fn(s: &CRustObjectSlice) -> &usize {
&s.len
}
let offset_our = ((&our_s.len as *const usize) as usize) - ((&our_s as *const MyCRustObjectSlice) as usize);
let offset_user = ((&user_s.len as *const usize) as usize) - ((&user_s as *const CRustObjectSlice) as usize);
assert_eq!(offset_our, offset_user);
#[allow(dead_code)]
fn check_CRustObjectSlice_step_type_fn(s: &CRustObjectSlice) -> &usize {
&s.step
}
let offset_our = ((&our_s.step as *const usize) as usize) - ((&our_s as *const MyCRustObjectSlice) as usize);
let offset_user = ((&user_s.step as *const usize) as usize) - ((&user_s as *const CRustObjectSlice) as usize);
assert_eq!(offset_our, offset_user);
}
#[allow(non_snake_case)]
#[test]
fn test_CRustObjectMutSlice_layout() {
#[repr(C)]
struct MyCRustObjectMutSlice {
data: *mut ::std::os::raw::c_void,
len: usize,
step: usize,
}
assert_eq!(::std::mem::size_of::<MyCRustObjectMutSlice>(), ::std::mem::size_of::<CRustObjectMutSlice>());
assert_eq!(::std::mem::align_of::<MyCRustObjectMutSlice>(), ::std::mem::align_of::<CRustObjectMutSlice>());
let our_s: MyCRustObjectMutSlice = unsafe { ::std::mem::zeroed() };
let user_s: CRustObjectMutSlice = unsafe { ::std::mem::zeroed() };
#[allow(dead_code)]
fn check_CRustObjectMutSlice_data_type_fn(s: &CRustObjectMutSlice) -> &*mut ::std::os::raw::c_void {
&s.data
}
let offset_our = ((&our_s.data as *const *mut ::std::os::raw::c_void) as usize) - ((&our_s as *const MyCRustObjectMutSlice) as usize);
let offset_user = ((&user_s.data as *const *mut ::std::os::raw::c_void) as usize) - ((&user_s as *const CRustObjectMutSlice) as usize);
assert_eq!(offset_our, offset_user);
#[allow(dead_code)]
fn check_CRustObjectMutSlice_len_type_fn(s: &CRustObjectMutSlice) -> &usize {
&s.len
}
let offset_our = ((&our_s.len as *const usize) as usize) - ((&our_s as *const MyCRustObjectMutSlice) as usize);
let offset_user = ((&user_s.len as *const usize) as usize) - ((&user_s as *const CRustObjectMutSlice) as usize);
assert_eq!(offset_our, offset_user);
#[allow(dead_code)]
fn check_CRustObjectMutSlice_step_type_fn(s: &CRustObjectMutSlice) -> &usize {
&s.step
}
let offset_our = ((&our_s.step as *const usize) as usize) - ((&our_s as *const MyCRustObjectMutSlice) as usize);
let offset_user = ((&user_s.step as *const usize) as usize) - ((&user_s as *const CRustObjectMutSlice) as usize);
assert_eq!(offset_our, offset_user);
}
#[allow(non_snake_case)]
#[test]
fn test_CRustSliceAccess_layout() {
#[repr(C)]
struct MyCRustSliceAccess {
data: *const ::std::os::raw::c_void,
len: usize,
}
assert_eq!(::std::mem::size_of::<MyCRustSliceAccess>(), ::std::mem::size_of::<CRustSliceAccess>());
assert_eq!(::std::mem::align_of::<MyCRustSliceAccess>(), ::std::mem::align_of::<CRustSliceAccess>());
let our_s: MyCRustSliceAccess = unsafe { ::std::mem::zeroed() };
let user_s: CRustSliceAccess = unsafe { ::std::mem::zeroed() };
#[allow(dead_code)]
fn check_CRustSliceAccess_data_type_fn(s: &CRustSliceAccess) -> &*const ::std::os::raw::c_void {
&s.data
}
let offset_our = ((&our_s.data as *const *const ::std::os::raw::c_void) as usize) - ((&our_s as *const MyCRustSliceAccess) as usize);
let offset_user = ((&user_s.data as *const *const ::std::os::raw::c_void) as usize) - ((&user_s as *const CRustSliceAccess) as usize);
assert_eq!(offset_our, offset_user);
#[allow(dead_code)]
fn check_CRustSliceAccess_len_type_fn(s: &CRustSliceAccess) -> &usize {
&s.len
}
let offset_our = ((&our_s.len as *const usize) as usize) - ((&our_s as *const MyCRustSliceAccess) as usize);
let offset_user = ((&user_s.len as *const usize) as usize) - ((&user_s as *const CRustSliceAccess) as usize);
assert_eq!(offset_our, offset_user);
}
#[allow(non_snake_case)]
#[test]
fn test_CRustVecAccess_layout() {
#[repr(C)]
struct MyCRustVecAccess {
data: *const ::std::os::raw::c_void,
len: usize,
capacity: usize,
}
assert_eq!(::std::mem::size_of::<MyCRustVecAccess>(), ::std::mem::size_of::<CRustVecAccess>());
assert_eq!(::std::mem::align_of::<MyCRustVecAccess>(), ::std::mem::align_of::<CRustVecAccess>());
let our_s: MyCRustVecAccess = unsafe { ::std::mem::zeroed() };
let user_s: CRustVecAccess = unsafe { ::std::mem::zeroed() };
#[allow(dead_code)]
fn check_CRustVecAccess_data_type_fn(s: &CRustVecAccess) -> &*const ::std::os::raw::c_void {
&s.data
}
let offset_our = ((&our_s.data as *const *const ::std::os::raw::c_void) as usize) - ((&our_s as *const MyCRustVecAccess) as usize);
let offset_user = ((&user_s.data as *const *const ::std::os::raw::c_void) as usize) - ((&user_s as *const CRustVecAccess) as usize);
assert_eq!(offset_our, offset_user);
#[allow(dead_code)]
fn check_CRustVecAccess_len_type_fn(s: &CRustVecAccess) -> &usize {
&s.len
}
let offset_our = ((&our_s.len as *const usize) as usize) - ((&our_s as *const MyCRustVecAccess) as usize);
let offset_user = ((&user_s.len as *const usize) as usize) - ((&user_s as *const CRustVecAccess) as usize);
assert_eq!(offset_our, offset_user);
#[allow(dead_code)]
fn check_CRustVecAccess_capacity_type_fn(s: &CRustVecAccess) -> &usize {
&s.capacity
}
let offset_our = ((&our_s.capacity as *const usize) as usize) - ((&our_s as *const MyCRustVecAccess) as usize);
let offset_user = ((&user_s.capacity as *const usize) as usize) - ((&user_s as *const CRustVecAccess) as usize);
assert_eq!(offset_our, offset_user);
}
#[allow(non_snake_case)]
#[test]
fn test_CRustForeignVec_layout() {
#[repr(C)]
struct MyCRustForeignVec {
data: *const ::std::os::raw::c_void,
len: usize,
capacity: usize,
}
assert_eq!(::std::mem::size_of::<MyCRustForeignVec>(), ::std::mem::size_of::<CRustForeignVec>());
assert_eq!(::std::mem::align_of::<MyCRustForeignVec>(), ::std::mem::align_of::<CRustForeignVec>());
let our_s: MyCRustForeignVec = unsafe { ::std::mem::zeroed() };
let user_s: CRustForeignVec = unsafe { ::std::mem::zeroed() };
#[allow(dead_code)]
fn check_CRustForeignVec_data_type_fn(s: &CRustForeignVec) -> &*const ::std::os::raw::c_void {
&s.data
}
let offset_our = ((&our_s.data as *const *const ::std::os::raw::c_void) as usize) - ((&our_s as *const MyCRustForeignVec) as usize);
let offset_user = ((&user_s.data as *const *const ::std::os::raw::c_void) as usize) - ((&user_s as *const CRustForeignVec) as usize);
assert_eq!(offset_our, offset_user);
#[allow(dead_code)]
fn check_CRustForeignVec_len_type_fn(s: &CRustForeignVec) -> &usize {
&s.len
}
let offset_our = ((&our_s.len as *const usize) as usize) - ((&our_s as *const MyCRustForeignVec) as usize);
let offset_user = ((&user_s.len as *const usize) as usize) - ((&user_s as *const CRustForeignVec) as usize);
assert_eq!(offset_our, offset_user);
#[allow(dead_code)]
fn check_CRustForeignVec_capacity_type_fn(s: &CRustForeignVec) -> &usize {
&s.capacity
}
let offset_our = ((&our_s.capacity as *const usize) as usize) - ((&our_s as *const MyCRustForeignVec) as usize);
let offset_user = ((&user_s.capacity as *const usize) as usize) - ((&user_s as *const CRustForeignVec) as usize);
assert_eq!(offset_our, offset_user);
}
impl SwigForeignClass for Foo {
fn c_class_name() -> *const ::std::os::raw::c_char {
swig_c_str!(stringify!(Foo))
}
fn box_object(this: Self) -> *mut ::std::os::raw::c_void {
let this: Box<Foo> = Box::new(this);
let this: *mut Foo = Box::into_raw(this);
this as *mut ::std::os::raw::c_void
}
fn unbox_object(p: *mut ::std::os::raw::c_void) -> Self {
let p = p as *mut Foo;
let p: Box<Foo> = unsafe { Box::from_raw(p) };
let p: Foo = *p;
p
}
}
#[allow(unused_variables, unused_mut, non_snake_case, unused_unsafe)]
#[no_mangle]
pub extern "C" fn Foo_new(val: i32) -> *const ::std::os::raw::c_void {
let this: Foo = Foo::new(val);
let this: Box<Foo> = Box::new(this);
let this: *mut Foo = Box::into_raw(this);
this as *const ::std::os::raw::c_void
}
#[allow(non_snake_case, unused_variables, unused_mut, unused_unsafe)]
#[no_mangle]
pub extern "C" fn Foo_f(this: *mut Foo, a: i32, b: i32) -> i32 {
let this: &Foo = unsafe { this.as_mut().unwrap() };
let mut ret: i32 = Foo::f(this, a, b);
ret
}
#[allow(non_snake_case, unused_variables, unused_mut, unused_unsafe)]
#[no_mangle]
pub extern "C" fn Foo_setField(this: *mut Foo, v: i32) -> () {
let this: &mut Foo = unsafe { this.as_mut().unwrap() };
let mut ret: () = Foo::set_field(this, v);
ret
}
#[allow(unused_variables, unused_mut, non_snake_case, unused_unsafe)]
#[no_mangle]
pub extern "C" fn Foo_delete(this: *mut Foo) {
let this: Box<Foo> = unsafe { Box::from_raw(this) };
drop(this);
}

View File

@@ -1,11 +0,0 @@
//Automatically generated by rifgen
use crate::*;
foreign_class!(
class Foo {
self_type Foo;
constructor Foo::new(val : i32)->Foo;
fn Foo::f(& self , a : i32 , b : i32)->i32; alias f;
# [doc = "Custom doc comment"]
fn Foo::set_field(& mut self , v : i32); alias setField;
}
);

View File

@@ -1,45 +0,0 @@
mod cpp_glue;
pub use crate::cpp_glue::*;
use rifgen::rifgen_attr::*;
extern crate velopack;
velopack::
pub struct Foo {
data: i32,
}
impl Foo {
#[generate_interface(constructor)]
fn new(val: i32) -> Foo {
Foo { data: val }
}
#[generate_interface]
fn f(&self, a: i32, b: i32) -> i32 {
self.data + a + b
}
///Custom doc comment
#[generate_interface]
fn set_field(&mut self, v: i32) {
self.data = v;
}
}
fn f2(a: i32) -> i32 {
a * 2
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn it_works() {
let foo = Foo::new(5);
assert_eq!(8, foo.f(1, 2));
}
}

View File

@@ -0,0 +1,7 @@
#ifndef VELOPACK_HPP
#define VELOPACK_HPP
#endif // VELOPACK_HPP

View File

@@ -0,0 +1,20 @@
#pragma once
#include "rust/cxx.h"
struct HookCallbackManager {
void install_hook(::rust::String app_version) const {};
void update_hook(::rust::String app_version) const {};
void obsolete_hook(::rust::String app_version) const {};
void uninstall_hook(::rust::String app_version) const {};
void firstrun_hook(::rust::String app_version) const {};
void restarted_hook(::rust::String app_version) const {};
};
struct DownloadCallbackManager {
void download_progress(int16_t progress) const {};
};
struct LoggerCallbackManager {
void log(::LogLevel level, ::rust::String message) const {};
};

View File

@@ -1,21 +0,0 @@
#include <cstdlib>
#include <iostream>
#include "Foo.hpp"
using namespace velopack_cpp;
int main()
{
// ANCHOR: call_rust
Foo foo(5);
int res = foo.f(1, 2);
// ANCHOR_END: call_rust
if (res == 8) {
std::cout << "All works fine\n";
}
else {
std::cout << "Something really BAD!!!\n";
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}

369
src/lib-cpp/src/lib.rs Normal file
View File

@@ -0,0 +1,369 @@
#![allow(non_snake_case)]
use anyhow::{anyhow, bail, Result};
use std::path::PathBuf;
use std::sync::{Arc, Mutex};
use std::sync::atomic::{AtomicUsize, Ordering};
use lazy_static::lazy_static;
use log::{Level, Log, Metadata, Record};
use velopack::{
locator::VelopackLocatorConfig,
UpdateManager,
UpdateCheck,
UpdateOptions as VelopackUpdateOptions,
UpdateInfo as VelopackUpdateInfo,
VelopackAsset,
VelopackApp,
Error as VelopackError,
sources,
};
#[cxx::bridge]
mod ffi {
// Shared structs with fields visible to both languages.
#[derive(Default)]
pub struct Asset {
pub PackageId: String,
pub Version: String,
pub Type: String,
pub FileName: String,
pub SHA1: String,
pub SHA256: String,
pub Size: u64,
pub NotesMarkdown: String,
pub NotesHtml: String,
}
pub struct AssetOption {
pub data: Asset,
pub has_data: bool,
}
#[derive(Default)]
pub struct UpdateInfo {
pub TargetFullRelease: Asset,
pub IsDowngrade: bool,
}
pub struct UpdateInfoOption {
pub data: UpdateInfo,
pub has_data: bool,
}
pub struct LocatorConfig<'a> {
pub RootAppDir: &'a CxxString,
pub UpdateExePath: &'a CxxString,
pub PackagesDir: &'a CxxString,
pub ManifestPath: &'a CxxString,
pub CurrentBinaryDir: &'a CxxString,
pub IsPortable: bool,
}
pub struct LocatorConfigOption<'a> {
pub data: LocatorConfig<'a>,
pub has_data: bool,
}
pub struct UpdateOptions<'a> {
pub AllowVersionDowngrade: bool,
pub ExplicitChannel: &'a CxxString,
}
pub struct StringArrayOption {
pub data: Vec<String>,
pub has_data: bool,
}
pub enum LogLevel {
Trace = 0,
Debug = 1,
Info = 2,
Warn = 3,
Error = 4,
}
// C++ types and signatures exposed to Rust.
unsafe extern "C++" {
include!("velopack_libc/include/bridge.hpp");
type HookCallbackManager;
fn install_hook(self: &HookCallbackManager, app_version: String);
fn update_hook(self: &HookCallbackManager, app_version: String);
fn obsolete_hook(self: &HookCallbackManager, app_version: String);
fn uninstall_hook(self: &HookCallbackManager, app_version: String);
fn firstrun_hook(self: &HookCallbackManager, app_version: String);
fn restarted_hook(self: &HookCallbackManager, app_version: String);
type DownloadCallbackManager;
fn download_progress(self: &DownloadCallbackManager, progress: i16);
type LoggerCallbackManager;
fn log(self: &LoggerCallbackManager, level: LogLevel, message: String);
}
// Rust types and signatures exposed to C++.
extern "Rust" {
type UpdateManagerOpaque;
fn bridge_new_update_manager(url_or_path: &CxxString, options: UpdateOptions, locator: LocatorConfigOption) -> Result<Box<UpdateManagerOpaque>>;
fn bridge_get_current_version(manager: &UpdateManagerOpaque) -> String;
fn bridge_get_app_id(manager: &UpdateManagerOpaque) -> String;
fn bridge_is_portable(manager: &UpdateManagerOpaque) -> bool;
fn bridge_update_pending_restart(manager: &UpdateManagerOpaque) -> AssetOption;
fn bridge_check_for_updates(manager: &UpdateManagerOpaque) -> Result<UpdateInfoOption>;
fn bridge_download_update(manager: &UpdateManagerOpaque, to_download: UpdateInfo, progress: UniquePtr<DownloadCallbackManager>) -> Result<()>;
fn bridge_wait_exit_then_apply_update(manager: &UpdateManagerOpaque, to_download: Asset, silent: bool, restart: bool, restart_args: Vec<String>) -> Result<()>;
fn bridge_appbuilder_run(cb: UniquePtr<HookCallbackManager>, custom_args: StringArrayOption, locator: LocatorConfigOption, auto_apply: bool);
fn bridge_set_logger_callback(cb: UniquePtr<LoggerCallbackManager>);
}
}
#[derive(Clone)]
struct UpdateManagerOpaque {
obj: UpdateManager,
}
fn to_locator_config(locator: &ffi::LocatorConfig) -> VelopackLocatorConfig {
VelopackLocatorConfig {
RootAppDir: PathBuf::from(locator.RootAppDir.to_string_lossy().to_string()),
UpdateExePath: PathBuf::from(locator.UpdateExePath.to_string_lossy().to_string()),
PackagesDir: PathBuf::from(locator.PackagesDir.to_string_lossy().to_string()),
ManifestPath: PathBuf::from(locator.ManifestPath.to_string_lossy().to_string()),
CurrentBinaryDir: PathBuf::from(locator.CurrentBinaryDir.to_string_lossy().to_string()),
IsPortable: locator.IsPortable,
}
}
fn to_update_options(options: &ffi::UpdateOptions) -> VelopackUpdateOptions {
let channel = options.ExplicitChannel.to_string_lossy().to_string();
VelopackUpdateOptions {
AllowVersionDowngrade: options.AllowVersionDowngrade,
ExplicitChannel: if channel.is_empty() { None } else { Some(channel) },
}
}
fn from_asset(asset: &VelopackAsset) -> ffi::Asset {
ffi::Asset {
PackageId: asset.PackageId.clone(),
Version: asset.Version.clone(),
Type: asset.Type.clone(),
FileName: asset.FileName.clone(),
SHA1: asset.SHA1.clone(),
SHA256: asset.SHA256.clone(),
Size: asset.Size,
NotesMarkdown: asset.NotesMarkdown.clone(),
NotesHtml: asset.NotesHtml.clone(),
}
}
fn to_asset(asset: &ffi::Asset) -> VelopackAsset {
VelopackAsset {
PackageId: asset.PackageId.clone(),
Version: asset.Version.clone(),
Type: asset.Type.clone(),
FileName: asset.FileName.clone(),
SHA1: asset.SHA1.clone(),
SHA256: asset.SHA256.clone(),
Size: asset.Size,
NotesMarkdown: asset.NotesMarkdown.clone(),
NotesHtml: asset.NotesHtml.clone(),
}
}
fn from_update_info(info: &VelopackUpdateInfo) -> ffi::UpdateInfo {
ffi::UpdateInfo {
TargetFullRelease: from_asset(&info.TargetFullRelease),
IsDowngrade: info.IsDowngrade,
}
}
fn to_update_info(info: &ffi::UpdateInfo) -> VelopackUpdateInfo {
VelopackUpdateInfo {
TargetFullRelease: to_asset(&info.TargetFullRelease),
IsDowngrade: info.IsDowngrade,
}
}
fn bridge_new_update_manager(url_or_path: &cxx::CxxString, options: ffi::UpdateOptions, locator: ffi::LocatorConfigOption) -> Result<Box<UpdateManagerOpaque>> {
let url = url_or_path.to_string_lossy();
let source = sources::AutoSource::new(&url);
let update_options = to_update_options(&options);
if locator.has_data {
let locator_config = to_locator_config(&locator.data);
let update_manager = UpdateManager::new(source, Some(update_options), Some(locator_config))?;
Ok(Box::new(UpdateManagerOpaque { obj: update_manager }))
} else {
let update_manager = UpdateManager::new(source, Some(update_options), None)?;
Ok(Box::new(UpdateManagerOpaque { obj: update_manager }))
}
}
fn bridge_get_current_version(manager: &UpdateManagerOpaque) -> String {
manager.obj.get_current_version_as_string()
}
fn bridge_get_app_id(manager: &UpdateManagerOpaque) -> String {
manager.obj.get_app_id()
}
fn bridge_is_portable(manager: &UpdateManagerOpaque) -> bool {
manager.obj.get_is_portable()
}
fn bridge_update_pending_restart(manager: &UpdateManagerOpaque) -> ffi::AssetOption {
if let Some(info) = manager.obj.get_update_pending_restart() {
let update = from_asset(&info);
ffi::AssetOption { data: update, has_data: true }
} else {
let default = ffi::Asset::default();
ffi::AssetOption { data: default, has_data: false }
}
}
fn bridge_check_for_updates(manager: &UpdateManagerOpaque) -> Result<ffi::UpdateInfoOption> {
if let UpdateCheck::UpdateAvailable(info) = manager.obj.check_for_updates()? {
let update = from_update_info(&info);
Ok(ffi::UpdateInfoOption { data: update, has_data: true })
} else {
let default = ffi::UpdateInfo::default();
Ok(ffi::UpdateInfoOption { data: default, has_data: false })
}
}
fn bridge_download_update(manager: &UpdateManagerOpaque, to_download: ffi::UpdateInfo, cb: cxx::UniquePtr<ffi::DownloadCallbackManager>) -> Result<()> {
// let info = to_update_info(&to_download);
//
// let (sender, receiver) = std::sync::mpsc::channel::<i16>();
// std::thread::spawn(move || {
// while let Ok(progress) = receiver.recv() {
// cb.download_progress(progress);
// }
// });
//
// manager.obj.download_updates(&info, Some(sender))?;
// Ok(())
let info = to_update_info(&to_download);
let (progress_sender, progress_receiver) = std::sync::mpsc::channel::<i16>();
let (completion_sender, completion_receiver) = std::sync::mpsc::channel::<std::result::Result<(), VelopackError>>();
// Move the download_updates call into a new thread
let manager = manager.clone();
std::thread::spawn(move || {
let result = manager.obj.download_updates(&info, Some(progress_sender));
let _ = completion_sender.send(result);
});
// Process progress updates on the caller's thread
loop {
// Try to receive progress updates without blocking
match progress_receiver.try_recv() {
Ok(progress) => {
cb.download_progress(progress);
}
_ => {
// No progress updates available, sleep for a short time to avoid busy-waiting
std::thread::sleep(std::time::Duration::from_millis(50));
}
}
// Check if download is complete
match completion_receiver.try_recv() {
Ok(result) => {
// Download is complete, return the result (propagating any errors)
result?;
return Ok(());
}
Err(std::sync::mpsc::TryRecvError::Empty) => {
// Download is still in progress, continue processing progress updates
}
Err(std::sync::mpsc::TryRecvError::Disconnected) => {
bail!("Download thread disconnected unexpectedly without returning a result");
}
}
}
}
fn bridge_wait_exit_then_apply_update(manager: &UpdateManagerOpaque, to_download: ffi::Asset, silent: bool, restart: bool, restart_args: Vec<String>) -> Result<()> {
let asset = to_asset(&to_download);
manager.obj.wait_exit_then_apply_updates(&asset, silent, restart, restart_args)?;
Ok(())
}
fn bridge_appbuilder_run(cb: cxx::UniquePtr<ffi::HookCallbackManager>, custom_args: ffi::StringArrayOption, locator: ffi::LocatorConfigOption, auto_apply: bool) {
let mut app = VelopackApp::build()
.on_first_run(|v| cb.firstrun_hook(v.to_string()))
.on_restarted(|v| cb.restarted_hook(v.to_string()))
.set_auto_apply_on_startup(auto_apply);
#[cfg(windows)]
{
app = app.on_after_install_fast_callback(|v| cb.install_hook(v.to_string()))
.on_after_update_fast_callback(|v| cb.update_hook(v.to_string()))
.on_before_update_fast_callback(|v| cb.obsolete_hook(v.to_string()))
.on_before_uninstall_fast_callback(|v| cb.uninstall_hook(v.to_string()));
}
if locator.has_data {
app = app.set_locator(to_locator_config(&locator.data));
}
if custom_args.has_data {
app = app.set_args(custom_args.data);
}
app.run();
}
struct LoggerImpl {}
static LOGGER: LoggerImpl = LoggerImpl {};
impl Log for LoggerImpl {
fn enabled(&self, metadata: &Metadata) -> bool {
metadata.level() <= log::max_level()
}
fn log(&self, record: &Record) {
if !self.enabled(record.metadata()) {
return;
}
let text = format!("{}", record.args());
let level = match record.level() {
Level::Error => ffi::LogLevel::Error,
Level::Warn => ffi::LogLevel::Warn,
Level::Info => ffi::LogLevel::Info,
Level::Debug => ffi::LogLevel::Debug,
Level::Trace => ffi::LogLevel::Trace,
};
if let Some(cb) = get_logger() {
cb.log(level, text);
}
}
fn flush(&self) {}
}
lazy_static::lazy_static! {
static ref LOGGER_CB: AtomicUsize = AtomicUsize::new(0);
}
fn store_logger(ptr: *mut ffi::LoggerCallbackManager) {
LOGGER_CB.store(ptr as usize, Ordering::SeqCst);
}
fn get_logger() -> Option<*mut ffi::LoggerCallbackManager> {
let ptr = LOGGER_CB.load(Ordering::SeqCst);
if ptr == 0 {
None
} else {
Some(ptr as *mut ffi::LoggerCallbackManager)
}
}
fn bridge_set_logger_callback(cb: cxx::UniquePtr<ffi::LoggerCallbackManager>) {
let cb = cb.into_raw();
store_logger(cb);
}