diff --git a/.gitignore b/.gitignore index 89192eb1..7e26f89c 100644 --- a/.gitignore +++ b/.gitignore @@ -11,6 +11,7 @@ cargo.log cross.log *.tgz *.node +out/ ################# ## Eclipse diff --git a/Cargo.lock b/Cargo.lock index e6a46028..8af41997 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -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" diff --git a/Cargo.toml b/Cargo.toml index 3e8e7784..763e8acd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -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" diff --git a/src/lib-cpp/CMakeLists.txt b/src/lib-cpp/CMakeLists.txt deleted file mode 100644 index ed2e5131..00000000 --- a/src/lib-cpp/CMakeLists.txt +++ /dev/null @@ -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}) diff --git a/src/lib-cpp/Cargo.toml b/src/lib-cpp/Cargo.toml new file mode 100644 index 00000000..03bb1049 --- /dev/null +++ b/src/lib-cpp/Cargo.toml @@ -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 \ No newline at end of file diff --git a/src/lib-cpp/api/Foo.hpp b/src/lib-cpp/api/Foo.hpp deleted file mode 100644 index 9def9887..00000000 --- a/src/lib-cpp/api/Foo.hpp +++ /dev/null @@ -1,108 +0,0 @@ -// Automatically generated by flapigen -#pragma once - -//for assert -#include -//for std::abort -#include -//for std::move -#include -//for std::conditional -#include - -#include - -#include "c_Foo.h" - -namespace velopack_cpp { - -template -class FooWrapper; -using Foo = FooWrapper; -using FooRef = FooWrapper; - - -template -class FooWrapper { -public: - using value_type = FooWrapper; - friend class FooWrapper; - friend class FooWrapper; - - using SelfType = typename std::conditional::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 as_rref() const noexcept { return FooWrapper{ self_ }; } - const FooWrapper &as_cref() const noexcept { return reinterpret_cast &>(*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 - inline int32_t FooWrapper::f(int32_t a, int32_t b) const noexcept - { - - int32_t ret = Foo_f(this->self_, a, b); - return ret; - } - - template - inline void FooWrapper::setField(int32_t v) noexcept - { - - Foo_setField(this->self_, v); - } - -} // namespace velopack_cpp diff --git a/src/lib-cpp/api/Foo_fwd.hpp b/src/lib-cpp/api/Foo_fwd.hpp deleted file mode 100644 index f15eb8be..00000000 --- a/src/lib-cpp/api/Foo_fwd.hpp +++ /dev/null @@ -1,9 +0,0 @@ -// Automatically generated by flapigen -#pragma once - -namespace velopack_cpp { -template -class FooWrapper; -using Foo = FooWrapper; -using FooRef = FooWrapper; -} // namespace velopack_cpp diff --git a/src/lib-cpp/api/c_Foo.h b/src/lib-cpp/api/c_Foo.h deleted file mode 100644 index f8a245da..00000000 --- a/src/lib-cpp/api/c_Foo.h +++ /dev/null @@ -1,28 +0,0 @@ -// Automatically generated by flapigen - -#pragma once - -//for (u)intX_t types -#include - -#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 - diff --git a/src/lib-cpp/api/rust_foreign_slice_impl.hpp b/src/lib-cpp/api/rust_foreign_slice_impl.hpp deleted file mode 100644 index ad48036e..00000000 --- a/src/lib-cpp/api/rust_foreign_slice_impl.hpp +++ /dev/null @@ -1,77 +0,0 @@ -#pragma once - -#include "rust_foreign_slice_iter.hpp" - -namespace velopack_cpp { -template -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; - using const_iterator = RustForeignSliceIterator; - - 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(this->data); - p += this->step * i; - auto elem_ptr = static_cast(static_cast(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(this->data); - p += this->step * this->len; - return iterator{ p, this->step }; - } - - const_iterator end() const noexcept - { - auto p = static_cast(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 diff --git a/src/lib-cpp/api/rust_foreign_slice_iter.hpp b/src/lib-cpp/api/rust_foreign_slice_iter.hpp deleted file mode 100644 index a1e33cf4..00000000 --- a/src/lib-cpp/api/rust_foreign_slice_iter.hpp +++ /dev/null @@ -1,131 +0,0 @@ -#pragma once - -#include //ptrdiff_t -#include -#include - -template 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(this->ptr); - return T{ elem_ptr }; - } - - RustForeignSliceIterator &operator++() noexcept - { - this->ptr = static_cast(this->ptr) + this->step; - return *this; - } - /*@}*/ - - /** - * \defgroup Bidirectional iterator requirements - */ - /*@{*/ - RustForeignSliceIterator &operator--() noexcept - { - this->ptr = static_cast(this->ptr) - this->step; - return *this; - } - /*@}*/ - /** - * \defgroup Random access iterator requirements - */ - /*@{*/ - T operator[](ptrdiff_t n) const noexcept - { - auto p = static_cast(this->ptr) + n * this->step; - auto elem_ptr = static_cast(p); - return T{ elem_ptr }; - } - - RustForeignSliceIterator &operator+=(ptrdiff_t n) noexcept - { - this->ptr = static_cast(this->ptr) + n * this->step; - return *this; - } - - RustForeignSliceIterator operator+(ptrdiff_t n) const noexcept - { - const void *p = static_cast(this->ptr) + n * this->step; - return RustForeignSliceIterator(p, this->step); - } - - RustForeignSliceIterator &operator-=(ptrdiff_t n) noexcept - { - this->ptr = static_cast(this->ptr) - n * this->step; - return *this; - } - - RustForeignSliceIterator operator-(ptrdiff_t n) const noexcept - { - const void *p = static_cast(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(this->ptr) - static_cast(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 &o) const noexcept - { - assert(this->step == o.step); - return this->ptr == o.ptr; - } - bool operator!=(const RustForeignSliceIterator &o) const noexcept { return !operator==(o); } - -private: - const void *ptr; - uintptr_t step; -}; diff --git a/src/lib-cpp/api/rust_foreign_vec_impl.hpp b/src/lib-cpp/api/rust_foreign_vec_impl.hpp deleted file mode 100644 index 532db413..00000000 --- a/src/lib-cpp/api/rust_foreign_vec_impl.hpp +++ /dev/null @@ -1,123 +0,0 @@ -#pragma once - -#include - -#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 RustForeignVec final : private CContainerType { -public: - using const_reference = ForeignClassRef; - using CForeignType = typename ForeignClassRef::CForeignType; - using value_type = typename ForeignClassRef::value_type; - using iterator = RustForeignSliceIterator; - using const_iterator = RustForeignSliceIterator; - - 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(this->data); - p += ELEM_SIZE * i; - auto elem_ptr = static_cast(static_cast(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(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(this->data); - p += ELEM_SIZE * this->len; - return iterator{ p, ELEM_SIZE }; - } - - const_iterator end() const noexcept - { - auto p = static_cast(this->data); - p += ELEM_SIZE * this->len; - return const_iterator{ p, ELEM_SIZE }; - } - - RustForeignSlice as_slice() const noexcept - { - return RustForeignSlice{ CRustObjectSlice{ - this->data, this->len, ELEM_SIZE } }; - } - - RustForeignSlice as_slice_mut() noexcept - { - return RustForeignSlice{ 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(std::alignment_of::value); - o.len = 0; - o.capacity = 0; - } -}; -} // namespace velopack_cpp diff --git a/src/lib-cpp/api/rust_slice.h b/src/lib-cpp/api/rust_slice.h deleted file mode 100644 index a67cb625..00000000 --- a/src/lib-cpp/api/rust_slice.h +++ /dev/null @@ -1,46 +0,0 @@ -// Automatically generated by flapigen -#pragma once - -//for (u)intX_t types -#include - -#ifdef __cplusplus -static_assert(sizeof(uintptr_t) == sizeof(uint8_t) * 8, - "our conversion usize <-> uintptr_t is wrong"); -#endif - #include - -#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 -using RustForeignSliceConst = RustForeignSlice; -} -#endif -#include - -#ifdef __cplusplus -extern "C" { -#endif -struct CRustSliceAccess { - /*const*/void * data; - uintptr_t len; -}; - -#ifdef __cplusplus -} // extern "C" { -#endif diff --git a/src/lib-cpp/api/rust_slice_access.hpp b/src/lib-cpp/api/rust_slice_access.hpp deleted file mode 100644 index 212f1df4..00000000 --- a/src/lib-cpp/api/rust_slice_access.hpp +++ /dev/null @@ -1,50 +0,0 @@ -#pragma once - -#include -#include - -#include "rust_slice.h" - -namespace velopack_cpp { -template 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 diff --git a/src/lib-cpp/api/rust_slice_mut.h b/src/lib-cpp/api/rust_slice_mut.h deleted file mode 100644 index 5fc53804..00000000 --- a/src/lib-cpp/api/rust_slice_mut.h +++ /dev/null @@ -1,33 +0,0 @@ -// Automatically generated by flapigen -#pragma once - -//for (u)intX_t types -#include - -#ifdef __cplusplus -static_assert(sizeof(uintptr_t) == sizeof(uint8_t) * 8, - "our conversion usize <-> uintptr_t is wrong"); -#endif - #include - -#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 -using RustForeignSliceMut = RustForeignSlice; -} -#endif diff --git a/src/lib-cpp/api/rust_slice_tmpl.hpp b/src/lib-cpp/api/rust_slice_tmpl.hpp deleted file mode 100644 index 9936e143..00000000 --- a/src/lib-cpp/api/rust_slice_tmpl.hpp +++ /dev/null @@ -1,59 +0,0 @@ -#pragma once - -#include -#include - -namespace velopack_cpp { - -template 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 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 diff --git a/src/lib-cpp/api/rust_str.h b/src/lib-cpp/api/rust_str.h deleted file mode 100644 index cd4c353e..00000000 --- a/src/lib-cpp/api/rust_str.h +++ /dev/null @@ -1,127 +0,0 @@ -// Automatically generated by flapigen -#pragma once - -//for (u)intX_t types -#include - -#ifdef __cplusplus -static_assert(sizeof(uintptr_t) == sizeof(uint8_t) * 8, - "our conversion usize <-> uintptr_t is wrong"); -#endif - #include - -#ifdef __cplusplus -extern "C" { -#endif -struct CRustStrView { - const char * data; - uintptr_t len; -}; - -#ifdef __cplusplus -} // extern "C" { -#endif -#include - -#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 - -#include - -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 diff --git a/src/lib-cpp/api/rust_vec.h b/src/lib-cpp/api/rust_vec.h deleted file mode 100644 index 5a601955..00000000 --- a/src/lib-cpp/api/rust_vec.h +++ /dev/null @@ -1,38 +0,0 @@ -// Automatically generated by flapigen -#pragma once - -//for (u)intX_t types -#include - -#ifdef __cplusplus -static_assert(sizeof(uintptr_t) == sizeof(uint8_t) * 8, - "our conversion usize <-> uintptr_t is wrong"); -#endif - #include - -#ifdef __cplusplus -extern "C" { -#endif -struct CRustVecAccess { - /*const*/void * data; - uintptr_t len; - uintptr_t capacity; -}; - -#ifdef __cplusplus -} // extern "C" { -#endif -#include - -#ifdef __cplusplus -extern "C" { -#endif -struct CRustForeignVec { - /*const*/void * data; - uintptr_t len; - uintptr_t capacity; -}; - -#ifdef __cplusplus -} // extern "C" { -#endif diff --git a/src/lib-cpp/api/rust_vec_access.hpp b/src/lib-cpp/api/rust_vec_access.hpp deleted file mode 100644 index 1460bea0..00000000 --- a/src/lib-cpp/api/rust_vec_access.hpp +++ /dev/null @@ -1,58 +0,0 @@ -#pragma once - -#include - -namespace velopack_cpp { -template -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 diff --git a/src/lib-cpp/api/rust_vec_impl.hpp b/src/lib-cpp/api/rust_vec_impl.hpp deleted file mode 100644 index 61892ce7..00000000 --- a/src/lib-cpp/api/rust_vec_impl.hpp +++ /dev/null @@ -1,78 +0,0 @@ -#pragma once - -#include - -namespace velopack_cpp { - -namespace internal { - template E field_type(E T::*); -} - -template -class RustVec final : private CContainerType { -public: - using value_type = - typename std::remove_const::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(std::alignment_of::value); - o.len = 0; - o.capacity = 0; - } -}; - -} // namespace velopack_cpp diff --git a/src/lib-cpp/build.rs b/src/lib-cpp/build.rs new file mode 100644 index 00000000..d834f950 --- /dev/null +++ b/src/lib-cpp/build.rs @@ -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"); +} \ No newline at end of file diff --git a/src/lib-cpp/generator/Cargo.toml b/src/lib-cpp/generator/Cargo.toml deleted file mode 100644 index 9dc29cdb..00000000 --- a/src/lib-cpp/generator/Cargo.toml +++ /dev/null @@ -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 = "*" \ No newline at end of file diff --git a/src/lib-cpp/generator/build.rs b/src/lib-cpp/generator/build.rs deleted file mode 100644 index bd954122..00000000 --- a/src/lib-cpp/generator/build.rs +++ /dev/null @@ -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(); -} diff --git a/src/lib-cpp/generator/src/cpp_glue.rs b/src/lib-cpp/generator/src/cpp_glue.rs deleted file mode 100644 index 7eaf50bb..00000000 --- a/src/lib-cpp/generator/src/cpp_glue.rs +++ /dev/null @@ -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 { - 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(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(mut v: Vec) -> 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(cs: Self) -> Vec { - 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(mut v: Vec) -> 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(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(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(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::(), ::std::mem::size_of::()); - assert_eq!(::std::mem::align_of::(), ::std::mem::align_of::()); - 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::(), ::std::mem::size_of::()); - assert_eq!(::std::mem::align_of::(), ::std::mem::align_of::()); - 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::(), ::std::mem::size_of::()); - assert_eq!(::std::mem::align_of::(), ::std::mem::align_of::()); - 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::(), ::std::mem::size_of::()); - assert_eq!(::std::mem::align_of::(), ::std::mem::align_of::()); - 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::(), ::std::mem::size_of::()); - assert_eq!(::std::mem::align_of::(), ::std::mem::align_of::()); - 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::(), ::std::mem::size_of::()); - assert_eq!(::std::mem::align_of::(), ::std::mem::align_of::()); - 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::(), ::std::mem::size_of::()); - assert_eq!(::std::mem::align_of::(), ::std::mem::align_of::()); - 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 = 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 = 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 = 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 = unsafe { Box::from_raw(this) }; - drop(this); -} diff --git a/src/lib-cpp/generator/src/cpp_glue.rs.in b/src/lib-cpp/generator/src/cpp_glue.rs.in deleted file mode 100644 index 6e714df8..00000000 --- a/src/lib-cpp/generator/src/cpp_glue.rs.in +++ /dev/null @@ -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; - } -); diff --git a/src/lib-cpp/generator/src/lib.rs b/src/lib-cpp/generator/src/lib.rs deleted file mode 100644 index 40497aa5..00000000 --- a/src/lib-cpp/generator/src/lib.rs +++ /dev/null @@ -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)); - } -} - diff --git a/src/lib-cpp/include/Velopack.hpp b/src/lib-cpp/include/Velopack.hpp new file mode 100644 index 00000000..0b7ed50e --- /dev/null +++ b/src/lib-cpp/include/Velopack.hpp @@ -0,0 +1,7 @@ +#ifndef VELOPACK_HPP +#define VELOPACK_HPP + + + + +#endif // VELOPACK_HPP \ No newline at end of file diff --git a/src/lib-cpp/include/bridge.hpp b/src/lib-cpp/include/bridge.hpp new file mode 100644 index 00000000..e637505a --- /dev/null +++ b/src/lib-cpp/include/bridge.hpp @@ -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 {}; +}; + diff --git a/src/lib-cpp/main.cpp b/src/lib-cpp/main.cpp deleted file mode 100644 index e16bffdf..00000000 --- a/src/lib-cpp/main.cpp +++ /dev/null @@ -1,21 +0,0 @@ -#include -#include - -#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; -} diff --git a/src/lib-cpp/src/lib.rs b/src/lib-cpp/src/lib.rs new file mode 100644 index 00000000..408fde0f --- /dev/null +++ b/src/lib-cpp/src/lib.rs @@ -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, + 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>; + 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; + fn bridge_download_update(manager: &UpdateManagerOpaque, to_download: UpdateInfo, progress: UniquePtr) -> Result<()>; + fn bridge_wait_exit_then_apply_update(manager: &UpdateManagerOpaque, to_download: Asset, silent: bool, restart: bool, restart_args: Vec) -> Result<()>; + fn bridge_appbuilder_run(cb: UniquePtr, custom_args: StringArrayOption, locator: LocatorConfigOption, auto_apply: bool); + fn bridge_set_logger_callback(cb: UniquePtr); + } +} + +#[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> { + 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 { + 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) -> Result<()> { + // let info = to_update_info(&to_download); + // + // let (sender, receiver) = std::sync::mpsc::channel::(); + // 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::(); + let (completion_sender, completion_receiver) = std::sync::mpsc::channel::>(); + + // 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) -> 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, 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) { + let cb = cb.into_raw(); + store_logger(cb); +} \ No newline at end of file