From 1fe907e969d5528aae0d3342f46d3def8514e6eb Mon Sep 17 00:00:00 2001 From: Jonathan Simms Date: Thu, 19 Jul 2018 09:21:28 -0400 Subject: [PATCH] rust support - Native bstrings (#160) Backport changes from pelikan to twitter/ccommon#186 Implement proper allocation/free for BString objects * All allocation of BStrings should happen from libc malloc() that way we don't mistakenly free something allocated from rust's allocator. * Drop should call libc's free() with the pointer, doing the correct thing. * This philosophy allows us to pass bstring pointers back and forth and not have to track which heap they're allocated on * Provide an implementation of a zero-cost reference object, much like String -> &str, we have BString -> &BStr. --- .gitignore | 2 + CMakeLists.txt | 8 +- include/cc_bstring.h | 3 + rust/CMakeLists.txt | 5 + rust/Cargo.lock | 495 +++++++++++++++++++++++++++++++++ rust/Cargo.toml | 21 ++ rust/cc_binding/CMakeLists.txt | 4 + rust/cc_binding/Cargo.toml | 11 + rust/cc_binding/build.rs | 69 +++++ rust/cc_binding/src/lib.rs | 8 + rust/cc_binding/wrapper.h | 2 + rust/ccommon_rs/CMakeLists.txt | 4 + rust/ccommon_rs/Cargo.toml | 12 + rust/ccommon_rs/src/bstring.rs | 460 ++++++++++++++++++++++++++++++ rust/ccommon_rs/src/lib.rs | 3 + src/cc_bstring.c | 32 +++ test/bstring/check_bstring.c | 21 ++ 17 files changed, 1159 insertions(+), 1 deletion(-) create mode 100644 rust/CMakeLists.txt create mode 100644 rust/Cargo.lock create mode 100644 rust/Cargo.toml create mode 100644 rust/cc_binding/CMakeLists.txt create mode 100644 rust/cc_binding/Cargo.toml create mode 100644 rust/cc_binding/build.rs create mode 100644 rust/cc_binding/src/lib.rs create mode 100644 rust/cc_binding/wrapper.h create mode 100644 rust/ccommon_rs/CMakeLists.txt create mode 100644 rust/ccommon_rs/Cargo.toml create mode 100644 rust/ccommon_rs/src/bstring.rs create mode 100644 rust/ccommon_rs/src/lib.rs diff --git a/.gitignore b/.gitignore index eb6da3567..781ba3860 100644 --- a/.gitignore +++ b/.gitignore @@ -42,3 +42,5 @@ tags # cscope cscope.* lcov + +CMAKE_BINARY_DIR diff --git a/CMakeLists.txt b/CMakeLists.txt index 47adbe801..6e7b64989 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -52,8 +52,8 @@ option(HAVE_ASSERT_PANIC "assert_panic disabled by default" OFF) option(HAVE_LOGGING "logging enabled by default" ON) option(HAVE_STATS "stats enabled by default" ON) option(HAVE_DEBUG_MM "debugging oriented memory management disabled by default" OFF) -option(HAVE_RUST "build rust components" OFF) option(COVERAGE "code coverage" OFF) +option(HAVE_RUST "rust bindings not built by default" OFF) if(BUILD_AND_INSTALL_CHECK) # (simms) What follows is a crime against build systems as we run the build/install @@ -123,6 +123,10 @@ set(CFLAGS_LIST string(REPLACE "" "" CFLAGS ${CFLAGS_LIST}) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${CFLAGS}") +if(CMAKE_COMPILER_IS_GNUCC) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wl,--no-as-needed -ldl -pthread -fPIC") +endif() + if (COVERAGE) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -O0 -Wall -W -fprofile-arcs -ftest-coverage") endif(COVERAGE) @@ -147,8 +151,10 @@ find_package(Threads) if(HAVE_RUST) enable_language(Rust) include(CMakeCargo) + add_subdirectory(rust) endif() + # where to find include files include_directories(${include_directories} "${PROJECT_BINARY_DIR}" diff --git a/include/cc_bstring.h b/include/cc_bstring.h index 65416dc6b..b82c8b3f5 100644 --- a/include/cc_bstring.h +++ b/include/cc_bstring.h @@ -56,6 +56,9 @@ rstatus_i bstring_duplicate(struct bstring *dst, const struct bstring *src); rstatus_i bstring_copy(struct bstring *dst, const char *src, uint32_t srclen); int bstring_compare(const struct bstring *s1, const struct bstring *s2); +struct bstring *bstring_alloc(uint32_t size); +void bstring_free(struct bstring **bstring); + /* TODO(yao): is this endian thing really useful? */ /* efficient implementation of string comparion of short strings */ #define str2cmp(m, c0, c1) \ diff --git a/rust/CMakeLists.txt b/rust/CMakeLists.txt new file mode 100644 index 000000000..808fb4391 --- /dev/null +++ b/rust/CMakeLists.txt @@ -0,0 +1,5 @@ +file(WRITE CMAKE_BINARY_DIR "${CMAKE_BINARY_DIR}\n") + +if(HAVE_RUST) + add_subdirectory(ccommon_rs) +endif() diff --git a/rust/Cargo.lock b/rust/Cargo.lock new file mode 100644 index 000000000..0dd65e2f3 --- /dev/null +++ b/rust/Cargo.lock @@ -0,0 +1,495 @@ +[[package]] +name = "aho-corasick" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "ansi_term" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "atty" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", + "termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "backtrace" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "backtrace-sys 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-demangle 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "backtrace-sys" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cc 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "bindgen" +version = "0.37.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cexpr 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "clang-sys 0.23.0 (registry+https://github.com/rust-lang/crates.io-index)", + "clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)", + "env_logger 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", + "peeking_take_while 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "which 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "bitflags" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "cc" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "cc_binding" +version = "0.1.0" +dependencies = [ + "bindgen 0.37.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "ccommon_rs" +version = "0.1.0" +dependencies = [ + "cc_binding 0.1.0", + "failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "cexpr" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "nom 3.2.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "cfg-if" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "clang-sys" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", + "libloading 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "clap" +version = "2.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "atty 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "textwrap 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "env_logger" +version = "0.5.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "atty 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", + "humantime 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "termcolor 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "failure" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "backtrace 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "failure_derive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "failure_derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)", + "synstructure 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "glob" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "humantime" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "lazy_static" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "libc" +version = "0.2.42" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "libloading" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cc 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "log" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "memchr" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "memchr" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "nom" +version = "3.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "memchr 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "peeking_take_while" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "proc-macro2" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "quick-error" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "quote" +version = "0.3.15" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "quote" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "redox_syscall" +version = "0.1.40" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "redox_termios" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "regex" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "aho-corasick 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "regex-syntax 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", + "thread_local 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "regex-syntax" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "ucd-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "strsim" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "syn" +version = "0.11.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", + "synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "synom" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "synstructure" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "termcolor" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "wincolor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "termion" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "textwrap" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "thread_local" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "lazy_static 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "ucd-util" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "unicode-width" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "unicode-xid" +version = "0.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "unicode-xid" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "unreachable" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "utf8-ranges" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "vec_map" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "void" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "which" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "winapi" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "wincolor" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[metadata] +"checksum aho-corasick 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "f0ba20154ea1f47ce2793322f049c5646cc6d0fa9759d5f333f286e507bf8080" +"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" +"checksum atty 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "2fc4a1aa4c24c0718a250f0681885c1af91419d242f29eb8f2ab28502d80dbd1" +"checksum backtrace 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "89a47830402e9981c5c41223151efcced65a0510c13097c769cede7efb34782a" +"checksum backtrace-sys 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)" = "bff67d0c06556c0b8e6b5f090f0eac52d950d9dfd1d35ba04e4ca3543eaf6a7e" +"checksum bindgen 0.37.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1b25ab82877ea8fe6ce1ce1f8ac54361f0218bad900af9eb11803994bf67c221" +"checksum bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d0c54bb8f454c567f21197eefcdbf5679d0bd99f2ddbe52e84c77061952e6789" +"checksum cc 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)" = "49ec142f5768efb5b7622aebc3fdbdbb8950a4b9ba996393cb76ef7466e8747d" +"checksum cexpr 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "42aac45e9567d97474a834efdee3081b3c942b2205be932092f53354ce503d6c" +"checksum cfg-if 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "efe5c877e17a9c717a0bf3613b2709f723202c4e4675cc8f12926ded29bcb17e" +"checksum clang-sys 0.23.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d7f7c04e52c35222fffcc3a115b5daf5f7e2bfb71c13c4e2321afe1fc71859c2" +"checksum clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b957d88f4b6a63b9d70d5f454ac8011819c6efa7727858f458ab71c756ce2d3e" +"checksum env_logger 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)" = "0e6e40ebb0e66918a37b38c7acab4e10d299e0463fe2af5d29b9cc86710cfd2a" +"checksum failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "934799b6c1de475a012a02dab0ace1ace43789ee4b99bcfbf1a2e3e8ced5de82" +"checksum failure_derive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c7cdda555bb90c9bb67a3b670a0f42de8e73f5981524123ad8578aafec8ddb8b" +"checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb" +"checksum humantime 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0484fda3e7007f2a4a0d9c3a703ca38c71c54c55602ce4660c419fd32e188c9e" +"checksum lazy_static 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e6412c5e2ad9584b0b8e979393122026cdd6d2a80b933f890dcd694ddbe73739" +"checksum libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)" = "b685088df2b950fccadf07a7187c8ef846a959c142338a48f9dc0b94517eb5f1" +"checksum libloading 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9c3ad660d7cb8c5822cd83d10897b0f1f1526792737a179e73896152f85b88c2" +"checksum log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "61bd98ae7f7b754bc53dca7d44b604f733c6bba044ea6f41bc8d89272d8161d2" +"checksum memchr 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "148fab2e51b4f1cfc66da2a7c32981d1d3c083a803978268bb11fe4b86925e7a" +"checksum memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "796fba70e76612589ed2ce7f45282f5af869e0fdd7cc6199fa1aa1f1d591ba9d" +"checksum nom 3.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05aec50c70fd288702bcd93284a8444607f3292dbdf2a30de5ea5dcdbe72287b" +"checksum peeking_take_while 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" +"checksum proc-macro2 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "77997c53ae6edd6d187fec07ec41b207063b5ee6f33680e9fa86d405cdd313d4" +"checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0" +"checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a" +"checksum quote 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9949cfe66888ffe1d53e6ec9d9f3b70714083854be20fd5e271b232a017401e8" +"checksum redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "c214e91d3ecf43e9a4e41e578973adeb14b474f2bee858742d127af75a0112b1" +"checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76" +"checksum regex 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "13c93d55961981ba9226a213b385216f83ab43bd6ac53ab16b2eeb47e337cf4e" +"checksum regex-syntax 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05b06a75f5217880fc5e905952a42750bf44787e56a6c6d6852ed0992f5e1d54" +"checksum rustc-demangle 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "76d7ba1feafada44f2d38eed812bd2489a03c0f5abb975799251518b68848649" +"checksum strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4f380125926a99e52bc279241539c018323fab05ad6368b56f93d9369ff550" +"checksum syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad" +"checksum synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6" +"checksum synstructure 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3a761d12e6d8dcb4dcf952a7a89b475e3a9d69e4a69307e01a470977642914bd" +"checksum termcolor 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "adc4587ead41bf016f11af03e55a624c06568b5a19db4e90fde573d805074f83" +"checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096" +"checksum textwrap 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "307686869c93e71f94da64286f9a9524c0f308a9e1c87a583de8e9c9039ad3f6" +"checksum thread_local 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "279ef31c19ededf577bfd12dfae728040a21f635b06a24cd670ff510edd38963" +"checksum ucd-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fd2be2d6639d0f8fe6cdda291ad456e23629558d466e2789d2c3e9892bda285d" +"checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526" +"checksum unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f860d7d29cf02cb2f3f359fd35991af3d30bac52c57d265a3c461074cb4dc" +"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" +"checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56" +"checksum utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "662fab6525a98beff2921d7f61a39e7d59e0b425ebc7d0d9e66d316e55124122" +"checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a" +"checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" +"checksum which 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e84a603e7e0b1ce1aa1ee2b109c7be00155ce52df5081590d1ffb93f4f515cb2" +"checksum winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "773ef9dcc5f24b7d850d0ff101e542ff24c3b090a9768e03ff889fdef41f00fd" +"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +"checksum wincolor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "eeb06499a3a4d44302791052df005d5232b927ed1a9658146d842165c4de7767" diff --git a/rust/Cargo.toml b/rust/Cargo.toml new file mode 100644 index 000000000..ae5821dad --- /dev/null +++ b/rust/Cargo.toml @@ -0,0 +1,21 @@ +[workspace] + +members = [ + "cc_binding", + "ccommon_rs", +] + +[profile.release] +opt-level = 3 +debug = true +rpath = false +lto = true +debug-assertions = false +codegen-units = 1 + +[profile.dev] +debug = true +opt-level = 0 + +[term] +verbose = true diff --git a/rust/cc_binding/CMakeLists.txt b/rust/cc_binding/CMakeLists.txt new file mode 100644 index 000000000..6c8be94ae --- /dev/null +++ b/rust/cc_binding/CMakeLists.txt @@ -0,0 +1,4 @@ +cargo_build(NAME cc_binding) + +add_dependencies(cc_binding_static ccommon-static) +add_dependencies(cc_binding_shared ccommon-shared) diff --git a/rust/cc_binding/Cargo.toml b/rust/cc_binding/Cargo.toml new file mode 100644 index 000000000..03d5ddc51 --- /dev/null +++ b/rust/cc_binding/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "cc_binding" +version = "0.1.0" +authors = ["Jonathan Simms "] + +[build-dependencies] +bindgen = "0.37.0" + +[lib] +name = "cc_binding" +crate-type = ["rlib", "dylib", "staticlib", "lib"] diff --git a/rust/cc_binding/build.rs b/rust/cc_binding/build.rs new file mode 100644 index 000000000..9960c66d1 --- /dev/null +++ b/rust/cc_binding/build.rs @@ -0,0 +1,69 @@ +extern crate bindgen; + +use std::env; +use std::fs; +use std::io; +use std::path::PathBuf; +use std::io::prelude::*; +use std::os::unix::fs as unix_fs; + +fn get_cmake_binary_dir() -> io::Result { + // this file is written by cmake on each run, updated with the location of + // the build directory. + let mut fp = fs::File::open("../CMAKE_BINARY_DIR")?; + let mut buf = String::new(); + let n = fp.read_to_string(&mut buf)?; + assert!(n > 0, "file was empty"); + Ok(String::from(buf.trim_right())) +} + +fn main() { + println!("cargo:rustc-link-lib=static=ccommon-1.2.0"); + + let include_path = fs::canonicalize("./../../include").unwrap(); + + let cmake_binary_dir = match get_cmake_binary_dir() { + Ok(p) => p, + Err(err) => panic!("Failed locating the CMAKE_BINARY_DIR file: {:#?}", err), + }; + + let cbd = PathBuf::from(cmake_binary_dir); + + let mut config_h_dir = cbd.clone(); + config_h_dir.push("ccommon"); + + let mut lib_dir = cbd.clone(); + lib_dir.push("lib"); + + println!("cargo:rustc-link-search=native={}", lib_dir.to_str().unwrap()); + + let bindings = bindgen::Builder::default() + .clang_args(vec![ + "-I", include_path.to_str().unwrap(), + "-I", config_h_dir.to_str().unwrap(), + "-I", cbd.to_str().unwrap(), + "-L", lib_dir.to_str().unwrap(), + ]) + .header("wrapper.h") + .blacklist_type("max_align_t") // https://github.com/rust-lang-nursery/rust-bindgen/issues/550 + .generate() + .expect("Unable to generate bindings"); + + let out_path = PathBuf::from(env::var("OUT_DIR").unwrap()); + bindings + .write_to_file(out_path.join("bindings.rs")) + .expect("Couldn't write bindings!"); + + // ./target/debug/build/cc_binding-27eac70f0fa2e180/out <<- starts here + + // cc_binding-27eac70f0fa2e180 + let symlink_content = + out_path.parent().unwrap().file_name().unwrap(); + + let build_dir = out_path.parent().and_then(|p| p.parent()).unwrap(); + + let link_location = build_dir.join("cc_binding"); + let _ = fs::remove_file(link_location.as_path()); + unix_fs::symlink(symlink_content, link_location).unwrap(); +} + diff --git a/rust/cc_binding/src/lib.rs b/rust/cc_binding/src/lib.rs new file mode 100644 index 000000000..2cf071191 --- /dev/null +++ b/rust/cc_binding/src/lib.rs @@ -0,0 +1,8 @@ +#![allow(unknown_lints)] +#![allow(clippy)] +#![allow(clippy_pedantic)] +#![allow(non_upper_case_globals)] +#![allow(non_camel_case_types)] +#![allow(non_snake_case)] +#![allow(dead_code)] +include!(concat!(env!("OUT_DIR"), "/bindings.rs")); diff --git a/rust/cc_binding/wrapper.h b/rust/cc_binding/wrapper.h new file mode 100644 index 000000000..c5b21b148 --- /dev/null +++ b/rust/cc_binding/wrapper.h @@ -0,0 +1,2 @@ +#include +#include diff --git a/rust/ccommon_rs/CMakeLists.txt b/rust/ccommon_rs/CMakeLists.txt new file mode 100644 index 000000000..f373e0938 --- /dev/null +++ b/rust/ccommon_rs/CMakeLists.txt @@ -0,0 +1,4 @@ +file(WRITE CMAKE_BINARY_DIR "${CMAKE_BINARY_DIR}\n") +cargo_build(NAME ccommon_rs) +add_dependencies(ccommon_rs_static ccommon-static) +add_dependencies(ccommon_rs_shared ccommon-shared) diff --git a/rust/ccommon_rs/Cargo.toml b/rust/ccommon_rs/Cargo.toml new file mode 100644 index 000000000..382bf2286 --- /dev/null +++ b/rust/ccommon_rs/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "ccommon_rs" +version = "0.1.0" +authors = ["Jonathan Simms "] + +[dependencies] + +cc_binding = { path = "../cc_binding" } + +log = "~0.4" +libc = "~0.2.42" +failure = "~0.1.1" diff --git a/rust/ccommon_rs/src/bstring.rs b/rust/ccommon_rs/src/bstring.rs new file mode 100644 index 000000000..b7eef4fb4 --- /dev/null +++ b/rust/ccommon_rs/src/bstring.rs @@ -0,0 +1,460 @@ +//! BString is a wrapper around a foreign allocated and freed pointer to a cc_bstring. +//! It takes care of creating and freeing the foreign pointer within the normal +//! Rust lifetime rules. It has a companion reference object BStr, and the relation +//! of BString to BStr is similar to the relationship between String and &str. +//! +//! # Safety +//! +//! The point of this module is to ensure safe interaction between +//! Rust and C, and to facilitate passing BStrings between the two +//! as the sized buffer of choice. +//! +//! Much like with the standard library collections (Vec, Box), one +//! cannot simply pass their `from_raw` methods any old pointer. +//! You must only pass pointers obtained via the `into_raw` method. +//! +//! # Undefined Behavior +//! +//! Creating a BString from a Rust-allocated `bind::bstring` struct +//! will lead to undefined behavior if it is allowed to Drop. BString's +//! Drop implmentation passes the contained pointer to libc's free method +//! which can lead to memory corruption and [nasal demons]. +//! +//! [nasal demons]: http://www.catb.org/jargon/html/N/nasal-demons.html + +use cc_binding as bind; +use std::borrow::Borrow; +use std::boxed::Box; +use std::cell::UnsafeCell; +use std::fmt; +use std::fmt::Debug; +use std::fmt::Formatter; +use std::mem; +use std::ops::{Deref, DerefMut}; +use std::slice; +use std::str; + + +pub type CCbstring = bind::bstring; + + +#[doc(hidden)] +#[inline] +unsafe fn raw_ptr_to_bytes<'a>(ptr: *const CCbstring) -> &'a [u8] { + slice::from_raw_parts( + (*ptr).data as *const _ as *const u8, + (*ptr).len as usize + ) +} + +#[doc(hidden)] +#[inline] +unsafe fn raw_ptr_to_bytes_mut<'a>(ptr: *mut CCbstring) -> &'a mut [u8] { + slice::from_raw_parts_mut( + (*ptr).data as *mut _ as *mut u8, + (*ptr).len as usize + ) +} + + +// this pattern lifted from https://docs.rs/foreign-types-shared/0.1.1/src/foreign_types_shared/lib.rs.html +struct Opaque(UnsafeCell<()>); + +/// A reference to a BString. String is to &str as BString is to &BStr. +/// This should be used when one does not want to take ownership of the +/// underlying pointer, but wants to access it in a rust-friendly way. +/// +/// This is useful in the case where the caller owns the buffer in the +/// data field and expects it to be filled (as opposed to in BString where +/// *we* own that memory). +/// +pub struct BStr(Opaque); + +impl BStr { + /// Wraps a raw pointer to a cc_bstring struct with a BStr. This is a + /// reference only conversion, and is zero cost. + #[inline] + pub unsafe fn from_ptr<'a>(ptr: *mut CCbstring) -> &'a Self { + &*(ptr as *mut _) + } + + /// Wraps a raw pointer to a cc_bstring struct with a BStr, and returns + /// a mutable reference. This is a reference only conversion, + /// and is zero cost. + #[inline] + pub unsafe fn from_ptr_mut<'a>(ptr: *mut CCbstring) -> &'a mut Self { + &mut *(ptr as *mut _) + } + + #[inline] + fn as_ptr(&self) -> *mut CCbstring { + self as *const _ as *mut _ + } +} + +impl Deref for BStr { + type Target = [u8]; + + #[inline] + fn deref(&self) -> &[u8] { + unsafe { raw_ptr_to_bytes(self.as_ptr()) } + } +} + +impl DerefMut for BStr { + #[inline] + fn deref_mut(&mut self) -> &mut [u8] { + unsafe { raw_ptr_to_bytes_mut(self.as_ptr()) } + } +} + +impl ToOwned for BStr { + type Owned = BString; + + #[inline] + fn to_owned(&self) -> BString { + unsafe { BString::from_raw(self.as_ptr()).clone() } + } +} + +unsafe impl Send for BStr {} +unsafe impl Sync for BStr {} + +/// An owned BString. By definition, a BString is allocated by +/// cc_bstring and freed by cc_bstring. This is because libc `malloc/free` +/// and Rust's `malloc/free` are two different implementations, and it's +/// important to keep track of who allocated what. To avoid this issue +/// all allocations are done from ccommon. +/// +/// This struct has Drop defined, and will call `bstring_free` when its +/// dropped. You can avoid this by using the `into_raw` method which +/// essentially leaks the memory. +/// +/// BString is safe for interoperation with ccommon libraries. You can pass +/// a pointer you got by using `BString::into_raw()` to C and everything will +/// just work. +/// +/// # Examples +/// +/// Creating and using a BString of a given size: +/// +/// ```rust +/// # use ccommon_rs::bstring::*; +/// +/// let mut bs = BString::new(3); +/// bs.copy_from_slice(&vec![0,1,2]); +/// +/// assert_eq!(&bs[..], &[0,1,2]) +/// ``` +/// +/// Creating an owned BString from Rust collections. If you can dereference it +/// to `&[u8]` you can copy it into a BString. +/// +/// ```rust +/// # use ccommon_rs::bstring::*; +/// +/// let s = BString::from("abc"); +/// assert_eq!(&s[..], "abc".as_bytes()); +/// +/// let v = BString::from(vec![0, 1, 2]); +/// assert_eq!(&v[..], &[0, 1, 2]); +/// ``` +/// +/// Mutating the content of a BString: +/// +/// ```rust +/// # use ccommon_rs::bstring::*; +/// +/// let mut s = BString::from("abc"); +/// s[0] = b'x'; +/// s[1] = b'y'; +/// s[2] = b'z'; +/// assert_eq!(&s[..], "xyz".as_bytes()); +/// ``` +/// +/// Use it as a buffer: +/// +/// ```rust +/// # use ccommon_rs::bstring::*; +/// use std::io::*; +/// use std::str; +/// +/// let mut x = BString::from("mutation is terrible "); +/// { +/// let mut c = Cursor::new(&mut x[..]); +/// let f = "fantastic".as_bytes(); +/// c.seek(SeekFrom::End(-9)); +/// +/// let sz = c.write(&f[..]).unwrap(); +/// assert_eq!(sz, f.len()); +/// } +/// +/// assert_eq!( +/// unsafe { str::from_utf8_unchecked(&x[..]) }, +/// "mutation is fantastic" +/// ); +/// ``` +/// +/// Note: if you're using BString as a buffer, it's important to +/// know that it *will not automatically resize*. If you write past the +/// end it will panic!. +pub struct BString(*mut CCbstring); + +impl BString { + pub fn new(size: u32) -> Self { + let bsp: *mut CCbstring = unsafe { bind::bstring_alloc(size) }; + + assert!(!bsp.is_null()); + BString(bsp) + } + + #[inline] + pub fn into_raw(bs: BString) -> *mut CCbstring { + let unique = bs.0; + mem::forget(bs); + unique + } + + #[inline] + pub unsafe fn from_raw(ptr: *mut CCbstring) -> BString { + assert!(!ptr.is_null()); + BString(ptr) + } + + /// Takes byte slice `&[u8]` and copies it into an owned BString. + #[inline] + pub fn from_bytes(s: &[u8]) -> Self { + let bsp: *mut CCbstring = unsafe { bind::bstring_alloc(s.len() as u32) }; + + assert!(!bsp.is_null()); + + let mut b = BString(bsp); + b.as_bytes_mut().clone_from_slice(&s[..]); + b + } + + /// Copies the contents of `src` into self. + /// + /// # Panics + /// + /// This method will panic if `src.len() != self.len()` + #[inline] + fn copy_from_slice(&mut self, src: &[u8]) { + assert_eq!(src.len(), self.len()); + (&mut (**self)).copy_from_slice(&src[..]); + } + + #[inline] + fn as_bytes(&self) -> &[u8] { + unsafe { raw_ptr_to_bytes(self.0) } + } + + #[inline] + fn as_bytes_mut(&mut self) -> &mut [u8] { + unsafe { raw_ptr_to_bytes_mut(self.0) } + } + + #[inline] + fn len(&self) -> usize { + unsafe { (*self.0).len as usize } + } +} + +impl Debug for BString { + fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> { + f.debug_struct("BString") + .field("len", &self.len()) + .field("data", &self.as_bytes()) + .finish() + } +} + +impl PartialEq for BString { + #[inline] + fn eq(&self, other: &BString) -> bool { + self.as_bytes().eq(other.as_bytes()) + } +} + +impl Drop for BString { + #[inline] + fn drop(&mut self) { + unsafe { bind::bstring_free(&mut self.0) }; + } +} + +impl Clone for BString { + /// Create a copy of both the underlying struct _and_ the data it points to. + #[inline] + fn clone(&self) -> Self { + BString::from_bytes(self.as_bytes()) + } +} + +impl Deref for BString { + type Target = BStr; + + #[inline] + fn deref(&self) -> &BStr { + unsafe { BStr::from_ptr(self.0) } + } +} + +impl DerefMut for BString { + #[inline] + fn deref_mut(&mut self) -> &mut BStr { + unsafe { BStr::from_ptr_mut(self.0) } + } +} + +impl AsMut for BString { + fn as_mut(&mut self) -> &mut BStr { + &mut (*self) + } +} + +impl AsRef for BString { + #[inline] + fn as_ref(&self) -> &BStr { + &*self + } +} + +impl Borrow for BString { + #[inline] + fn borrow(&self) -> &BStr { + &*self + } +} + +impl From> for BString { + #[inline] + fn from(v: Vec) -> Self { + BString::from_bytes(&v[..]) + } +} + +impl From for Vec { + #[inline] + fn from(bs: BString) -> Self { + let mut v = Vec::with_capacity(bs.len()); + v.copy_from_slice(&**bs); // &**bs is &(BString -> BStr -> [u8]) + v + } +} + +impl From> for BString { + #[inline] + fn from(b: Box<[u8]>) -> Self { + BString::from_bytes(&b[..]) + } +} + +impl<'a> From<&'a str> for BString { + #[inline] + fn from(s: &'a str) -> Self { + BString::from_bytes(s.as_bytes()) + } +} + +unsafe impl Send for BString {} +unsafe impl Sync for BString {} + + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn test_raw_ptr_to_bytes() { + let bs = CCbstring { + len: 5, + data: String::from("abcde").as_ptr() as *mut i8 + }; + + let ptr: *const CCbstring = &bs as *const CCbstring; + + let slice = unsafe { raw_ptr_to_bytes(ptr) }; + assert_eq!(slice.len(), 5); + assert_eq!(&slice[..], "abcde".as_bytes()); + } + + #[test] + fn test_raw_ptr_to_bytes_mut() { + let mut bs = BString::new(5); + BString::copy_from_slice(&mut bs, "abcde".as_bytes()); + + let ptr: *const CCbstring = BString::into_raw(bs) as *const CCbstring; + + { + let s = unsafe { raw_ptr_to_bytes_mut(ptr as *mut _) }; + s[0] = 0; + } + + let s = unsafe { raw_ptr_to_bytes(ptr) }; + assert_eq!(s[0], 0); + } + + #[test] + fn test_bstring_from_str() { + let bs = BString::from("wat"); + + assert_eq!(bs.as_bytes(), "wat".as_bytes()); + } + + #[test] + fn test_bstring_into_raw_pointer_remains_valid() { + let bsp: *mut CCbstring; + { + let mut bs = BString::new(5); + bs[0] = 12u8; + bsp = BString::into_raw(bs); + } + + // the bsp pointer should still be valid here even though bs has been dropped + let bytes = unsafe { raw_ptr_to_bytes(bsp) }; + assert_eq!(bytes[0], 12u8); + } + + #[test] + fn test_bstring_copy_from_slice() { + let mut bs = BString::new(5); + bs.copy_from_slice("abcde".as_bytes()); + assert_eq!(&bs[..], "abcde".as_bytes()); + } + + fn foreign_code(s: &str) -> *mut CCbstring { + BString::into_raw(BString::from(s)) + } + + #[test] + fn test_bstr_from_ptr() { + let s = "abc"; + let ptr: *mut CCbstring = foreign_code(s); + let bstr = unsafe { BStr::from_ptr(ptr) }; + assert_eq!(bstr.len(), 3); + assert_eq!(&bstr[..], &s.as_bytes()[..]); + + unsafe { BString::from_raw(ptr) }; + } + + #[test] + fn test_bstring_as_io_write() { + use std::io::*; + + let mut x = BString::from("mutation is terrible "); + { + let mut c = Cursor::new(&mut x[..]); + let f = "fantastic".as_bytes(); + c.seek(SeekFrom::End(-9)); + + let sz = c.write(&f[..]).unwrap(); + assert_eq!(sz, f.len()); + } + + assert_eq!( + unsafe { str::from_utf8_unchecked(&x[..]) }, + "mutation is fantastic" + ); + } +} diff --git a/rust/ccommon_rs/src/lib.rs b/rust/ccommon_rs/src/lib.rs new file mode 100644 index 000000000..6d035da4d --- /dev/null +++ b/rust/ccommon_rs/src/lib.rs @@ -0,0 +1,3 @@ +extern crate cc_binding; +extern crate failure; +pub mod bstring; diff --git a/src/cc_bstring.c b/src/cc_bstring.c index bb6b1d52a..58f40ca24 100644 --- a/src/cc_bstring.c +++ b/src/cc_bstring.c @@ -142,3 +142,35 @@ bstring_atou64(uint64_t *u64, struct bstring *str) return CC_OK; } + +struct bstring * +bstring_alloc(uint32_t size) +{ + struct bstring *bs = cc_alloc(sizeof(*bs)); + if (bs == NULL) { + return NULL; + } + bstring_init(bs); + + bs->len = size; + bs->data = cc_alloc(size); + if (bs->data == NULL) { + cc_free(bs); + return NULL; + } + + return bs; +} + +void +bstring_free(struct bstring **ptr) +{ + if ((ptr == NULL) || (*ptr == NULL)) { + return; + } + + struct bstring *bs = *ptr; + cc_free(bs->data); + cc_free(bs); + *ptr = NULL; +} diff --git a/test/bstring/check_bstring.c b/test/bstring/check_bstring.c index 9286732df..352b04398 100644 --- a/test/bstring/check_bstring.c +++ b/test/bstring/check_bstring.c @@ -130,6 +130,26 @@ START_TEST(test_atou64) } END_TEST +START_TEST(test_bstring_alloc_and_free) +{ +#define BSTRING_SIZE 9000 + + struct bstring *bs; + + bs = bstring_alloc(BSTRING_SIZE); + ck_assert_uint_eq(bs->len, BSTRING_SIZE); + for (int i = 0; i < BSTRING_SIZE; i++) { + bs->data[i] = 'a'; + } + + /* great! we didn't segfault! */ + bstring_free(&bs); + ck_assert_ptr_null(bs); + +#undef BSTRING_SIZE +} +END_TEST + /* * test suite */ @@ -146,6 +166,7 @@ bstring_suite(void) tcase_add_test(tc_bstring, test_copy); tcase_add_test(tc_bstring, test_compare); tcase_add_test(tc_bstring, test_atou64); + tcase_add_test(tc_bstring, test_bstring_alloc_and_free); return s; }