You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@opendal.apache.org by xu...@apache.org on 2025/04/18 01:49:03 UTC
(opendal) branch main updated: feat(bindings/cpp) remove lib.rs.h from opendal.hpp (#6041)
This is an automated email from the ASF dual-hosted git repository.
xuanwo pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/opendal.git
The following commit(s) were added to refs/heads/main by this push:
new 155023f53 feat(bindings/cpp) remove lib.rs.h from opendal.hpp (#6041)
155023f53 is described below
commit 155023f53335cb8461129ce808edd7dc0fc454a7
Author: deadlinefen <de...@bupt.edu.cn>
AuthorDate: Fri Apr 18 09:48:57 2025 +0800
feat(bindings/cpp) remove lib.rs.h from opendal.hpp (#6041)
* feat(bindings/cpp) remove lib.rs.h from opendal.hpp
* fix(bindings/cpp): fix missing include header in operator.hpp
Signed-off-by: Jack Drogon <ja...@gmail.com>
* fix(example/cpp): fix CMakeLists.txt to use local cpp bindings
Signed-off-by: Jack Drogon <ja...@gmail.com>
* chore(bindings/cpp): fix license with blank line && format code
Signed-off-by: Jack Drogon <ja...@gmail.com>
---------
Signed-off-by: Jack Drogon <ja...@gmail.com>
Co-authored-by: Jack Drogon <ja...@gmail.com>
---
bindings/cpp/CMakeLists.txt | 10 +-
bindings/cpp/include/opendal.hpp | 66 +++++++------
bindings/cpp/src/details/common.hpp | 46 +++++++++
bindings/cpp/src/details/lister.hpp | 58 +++++++++++
bindings/cpp/src/details/operator.cpp | 84 ++++++++++++++++
bindings/cpp/src/details/operator.hpp | 75 +++++++++++++++
bindings/cpp/src/details/reader.cpp | 48 ++++++++++
bindings/cpp/src/details/reader.hpp | 51 ++++++++++
bindings/cpp/src/opendal.cpp | 175 ++++++++++++++++------------------
bindings/cpp/tests/basic_test.cpp | 18 ++--
examples/cpp/CMakeLists.txt | 10 +-
examples/cpp/basic.cpp | 15 ++-
12 files changed, 513 insertions(+), 143 deletions(-)
diff --git a/bindings/cpp/CMakeLists.txt b/bindings/cpp/CMakeLists.txt
index 2762a1430..e3548f9f5 100644
--- a/bindings/cpp/CMakeLists.txt
+++ b/bindings/cpp/CMakeLists.txt
@@ -97,7 +97,15 @@ if (CMAKE_BUILD_TYPE STREQUAL "Debug")
else()
set(RUST_LIB ${CARGO_TARGET_DIR}/release/${CMAKE_STATIC_LIBRARY_PREFIX}opendal_cpp${CMAKE_STATIC_LIBRARY_SUFFIX})
endif()
-set(CPP_INCLUDE_DIR ${PROJECT_SOURCE_DIR}/include ${CARGO_TARGET_DIR}/cxxbridge/opendal-cpp/src)
+
+set(CPP_INCLUDE_DIR ${PROJECT_SOURCE_DIR}/include
+ ${PROJECT_SOURCE_DIR}/src
+ ${CARGO_TARGET_DIR}/cxxbridge
+ ${CARGO_TARGET_DIR}/cxxbridge/opendal-cpp/src)
+
+file(GLOB CPP_SOURCE_FILE "src/details/*.cpp")
+file(GLOB CPP_HEADER_FILE "src/details/*.hpp")
+
list(APPEND CPP_SOURCE_FILE src/opendal.cpp)
list(APPEND CPP_HEADER_FILE include/opendal.hpp)
if (OPENDAL_ENABLE_ASYNC)
diff --git a/bindings/cpp/include/opendal.hpp b/bindings/cpp/include/opendal.hpp
index cbf96476d..a5e4b901e 100644
--- a/bindings/cpp/include/opendal.hpp
+++ b/bindings/cpp/include/opendal.hpp
@@ -19,24 +19,29 @@
#pragma once
-#include <memory>
+#include <cstdint>
#include <optional>
#include <string>
#include <unordered_map>
#include <vector>
-#include "boost/date_time/posix_time/posix_time.hpp"
+#include "boost/date_time/posix_time/ptime.hpp"
#include "boost/iostreams/concepts.hpp"
#include "boost/iostreams/stream.hpp"
-#include "lib.rs.h"
namespace opendal {
+namespace details {
+class Operator;
+class Reader;
+class Lister;
+} // namespace details
+
/**
* @enum EntryMode
* @brief The mode of the entry
*/
-enum EntryMode {
+enum class EntryMode : int {
FILE = 1,
DIR = 2,
UNKNOWN = 0,
@@ -55,8 +60,6 @@ struct Metadata {
std::optional<std::string> content_type;
std::optional<std::string> etag;
std::optional<boost::posix_time::ptime> last_modified;
-
- Metadata(ffi::Metadata &&);
};
/**
@@ -65,8 +68,6 @@ struct Metadata {
*/
struct Entry {
std::string path;
-
- Entry(ffi::Entry &&);
};
class Reader;
@@ -78,7 +79,7 @@ class Lister;
*/
class Operator {
public:
- Operator() = default;
+ Operator();
/**
* @brief Construct a new Operator object
@@ -94,9 +95,10 @@ class Operator {
Operator &operator=(const Operator &) = delete;
// Enable move
- Operator(Operator &&) = default;
- Operator &operator=(Operator &&) = default;
- ~Operator() = default;
+ Operator(Operator &&);
+ Operator &operator=(Operator &&);
+
+ ~Operator();
/**
* @brief Check if the operator is available
@@ -113,7 +115,7 @@ class Operator {
* @param path The path of the data
* @return The data read from the operator
*/
- std::vector<uint8_t> read(std::string_view path);
+ std::string read(std::string_view path);
/**
* @brief Write data to the operator
@@ -121,7 +123,7 @@ class Operator {
* @param path The path of the data
* @param data The data to write
*/
- void write(std::string_view path, const std::vector<uint8_t> &data);
+ void write(std::string_view path, std::string_view data);
/**
* @brief Read data from the operator
@@ -198,7 +200,7 @@ class Operator {
Lister lister(std::string_view path);
private:
- std::optional<rust::Box<opendal::ffi::Operator>> operator_;
+ std::unique_ptr<details::Operator> operator_;
};
/**
@@ -213,14 +215,18 @@ class Operator {
class Reader
: public boost::iostreams::device<boost::iostreams::input_seekable> {
public:
- Reader(rust::Box<opendal::ffi::Reader> &&reader)
- : raw_reader_(std::move(reader)) {}
+ Reader(std::unique_ptr<details::Reader> &&reader);
+
+ Reader(Reader &&);
+
+ ~Reader();
std::streamsize read(void *s, std::streamsize n);
+
std::streampos seek(std::streamoff off, std::ios_base::seekdir way);
private:
- rust::Box<opendal::ffi::Reader> raw_reader_;
+ std::unique_ptr<details::Reader> raw_reader_;
};
// Boost IOStreams requires it to be copyable. So we need to use
@@ -259,8 +265,11 @@ class ReaderStream
*/
class Lister {
public:
- Lister(rust::Box<opendal::ffi::Lister> &&lister)
- : raw_lister_(std::move(lister)) {}
+ Lister(std::unique_ptr<details::Lister> lister);
+
+ Lister(Lister &&);
+
+ ~Lister();
/**
* @class ListerIterator
@@ -268,7 +277,7 @@ class Lister {
* @note It's an undefined behavior to make multiple iterators from one
* Lister.
*/
- class ListerIterator {
+ class Iterator {
public:
using iterator_category = std::input_iterator_tag;
using value_type = Entry;
@@ -276,27 +285,27 @@ class Lister {
using pointer = Entry *;
using reference = Entry &;
- ListerIterator(Lister &lister) : lister_(lister) {
+ Iterator(Lister &lister) : lister_{lister} {
current_entry_ = lister_.next();
}
Entry operator*() { return current_entry_.value(); }
- ListerIterator &operator++() {
+ Iterator &operator++() {
if (current_entry_) {
current_entry_ = lister_.next();
}
return *this;
}
- bool operator!=(const ListerIterator &other) const {
+ bool operator!=(const Iterator &other) const {
return current_entry_ != std::nullopt ||
other.current_entry_ != std::nullopt;
}
protected:
// Only used for end iterator
- ListerIterator(Lister &lister, bool /*end*/) : lister_(lister) {}
+ Iterator(Lister &lister, bool /*end*/) : lister_(lister) {}
private:
Lister &lister_;
@@ -312,10 +321,11 @@ class Lister {
*/
std::optional<Entry> next();
- ListerIterator begin() { return ListerIterator(*this); }
- ListerIterator end() { return ListerIterator(*this, true); }
+ Iterator begin() { return Iterator(*this); }
+ Iterator end() { return Iterator(*this, true); }
private:
- rust::Box<opendal::ffi::Lister> raw_lister_;
+ std::unique_ptr<details::Lister> raw_lister_;
};
+
} // namespace opendal
diff --git a/bindings/cpp/src/details/common.hpp b/bindings/cpp/src/details/common.hpp
new file mode 100644
index 000000000..bc0e44923
--- /dev/null
+++ b/bindings/cpp/src/details/common.hpp
@@ -0,0 +1,46 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#pragma once
+
+#include "rust/cxx.h"
+
+namespace opendal::details {
+
+template <typename T>
+auto rust_str(T &&s) -> decltype(s.data(), s.size(), rust::Str()) {
+ return rust::Str(s.data(), s.size());
+}
+
+template <typename T>
+auto rust_string(T &&s) -> decltype(s.data(), s.size(), rust::String()) {
+ return rust::String(s.data(), s.size());
+}
+
+template <typename T, typename Container>
+auto rust_slice(Container &&s)
+ -> decltype(s.data(), s.size(), rust::Slice<T>()) {
+ using Elem = std::remove_pointer_t<decltype(s.data())>;
+ static_assert(std::is_convertible_v<Elem, T>,
+ "Container element type must be convertible to T");
+
+ return rust::Slice<T>(reinterpret_cast<T *>(s.data()), s.size());
+}
+
+} // namespace opendal::details
diff --git a/bindings/cpp/src/details/lister.hpp b/bindings/cpp/src/details/lister.hpp
new file mode 100644
index 000000000..f135a3e26
--- /dev/null
+++ b/bindings/cpp/src/details/lister.hpp
@@ -0,0 +1,58 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#pragma once
+
+#include "lib.rs.h"
+
+/**
+ * @class Lister
+ * @brief Lister is designed to list the entries of a directory.
+ * @details It provides next operation to get the next entry. You can also use
+ * it like an iterator.
+ * @code{.cpp}
+ * auto lister = operator.lister("dir/");
+ * for (const auto &entry : lister) {
+ * // Do something with entry
+ * }
+ * @endcode
+ */
+namespace opendal::details {
+
+class Lister {
+ public:
+ Lister(rust::Box<opendal::ffi::Lister> &&lister)
+ : raw_lister_{std::move(lister)} {}
+
+ Lister(Lister &&) = default;
+
+ ~Lister() = default;
+
+ /**
+ * @brief Get the next entry of the lister
+ *
+ * @return The next entry of the lister
+ */
+ ffi::OptionalEntry next() { return raw_lister_->next(); }
+
+ private:
+ rust::Box<opendal::ffi::Lister> raw_lister_;
+};
+
+} // namespace opendal::details
diff --git a/bindings/cpp/src/details/operator.cpp b/bindings/cpp/src/details/operator.cpp
new file mode 100644
index 000000000..3596c91ec
--- /dev/null
+++ b/bindings/cpp/src/details/operator.cpp
@@ -0,0 +1,84 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include "details/operator.hpp"
+
+#include "details/common.hpp"
+#include "lib.rs.h"
+
+namespace opendal::details {
+
+rust::Box<opendal::ffi::Operator> Operator::create_by_config(
+ std::string_view scheme,
+ const std::unordered_map<std::string, std::string> &config) {
+ auto rust_map = rust::Vec<ffi::HashMapValue>();
+ rust_map.reserve(config.size());
+ for (auto &[k, v] : config) {
+ rust_map.push_back({rust_string(k), rust_string(v)});
+ }
+
+ return opendal::ffi::new_operator(rust_str(scheme), rust_map);
+}
+
+std::string Operator::read(std::string_view path) {
+ auto rust_vec = operator_->read(rust_str(path));
+ return {rust_vec.data(), rust_vec.data() + rust_vec.size()};
+}
+
+void Operator::write(std::string_view path, std::string_view data) {
+ operator_->write(rust_str(path), rust_slice<const uint8_t>(data));
+}
+
+rust::Box<ffi::Reader> Operator::reader(std::string_view path) {
+ return operator_->reader(rust_str(path));
+}
+
+bool Operator::exists(std::string_view path) {
+ return operator_->exists(rust_str(path));
+}
+
+void Operator::create_dir(std::string_view path) {
+ operator_->create_dir(rust_str(path));
+}
+
+void Operator::copy(std::string_view src, std::string_view dst) {
+ operator_->copy(rust_str(src), rust_str(dst));
+}
+
+void Operator::rename(std::string_view src, std::string_view dst) {
+ operator_->rename(rust_str(src), rust_str(dst));
+}
+
+void Operator::remove(std::string_view path) {
+ operator_->remove(rust_str(path));
+}
+
+ffi::Metadata Operator::stat(std::string_view path) {
+ return operator_->stat(rust_str(path));
+}
+
+rust::Vec<ffi::Entry> Operator::list(std::string_view path) {
+ return operator_->list(rust_str(path));
+}
+
+rust::Box<ffi::Lister> Operator::lister(std::string_view path) {
+ return operator_->lister(rust_str(path));
+}
+
+} // namespace opendal::details
diff --git a/bindings/cpp/src/details/operator.hpp b/bindings/cpp/src/details/operator.hpp
new file mode 100644
index 000000000..41ab9977b
--- /dev/null
+++ b/bindings/cpp/src/details/operator.hpp
@@ -0,0 +1,75 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#pragma once
+
+#include <string>
+#include <string_view>
+#include <unordered_map>
+
+#include "lib.rs.h"
+
+namespace opendal::details {
+
+class Operator {
+ public:
+ Operator(std::string_view scheme,
+ const std::unordered_map<std::string, std::string> &config = {})
+ : operator_(create_by_config(scheme, config)) {}
+
+ Operator(const Operator &) = delete;
+ Operator &operator=(const Operator &) = delete;
+
+ Operator(Operator &&) = default;
+ Operator &operator=(Operator &&) = default;
+ ~Operator() = default;
+
+ std::string read(std::string_view path);
+
+ void write(std::string_view path, std::string_view data);
+
+ rust::Box<ffi::Reader> reader(std::string_view path);
+
+ bool exists(std::string_view path);
+
+ void create_dir(std::string_view path);
+
+ void copy(std::string_view src, std::string_view dst);
+
+ void rename(std::string_view src, std::string_view dst);
+
+ void remove(std::string_view path);
+
+ ffi::Metadata stat(std::string_view path);
+
+ rust::Vec<ffi::Entry> list(std::string_view path);
+
+ rust::Box<ffi::Lister> lister(std::string_view path);
+
+ private:
+ using OperatorBox = rust::Box<opendal::ffi::Operator>;
+ using ConfigMap = std::unordered_map<std::string, std::string>;
+
+ OperatorBox create_by_config(std::string_view scheme,
+ const ConfigMap &config);
+
+ OperatorBox operator_;
+};
+
+} // namespace opendal::details
diff --git a/bindings/cpp/src/details/reader.cpp b/bindings/cpp/src/details/reader.cpp
new file mode 100644
index 000000000..8814a419b
--- /dev/null
+++ b/bindings/cpp/src/details/reader.cpp
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include "details/reader.hpp"
+
+namespace opendal::details {
+
+ffi::SeekDir rust_seek_dir(std::ios_base::seekdir dir) {
+ switch (dir) {
+ case std::ios_base::beg:
+ return ffi::SeekDir::Start;
+
+ case std::ios_base::cur:
+ return ffi::SeekDir::Current;
+
+ case std::ios_base::end:
+ return ffi::SeekDir::End;
+
+ default:
+ throw std::runtime_error("invalid seekdir");
+ }
+}
+
+std::size_t Reader::read(void *s, std::size_t n) {
+ return reader_->read(rust::Slice<uint8_t>(static_cast<uint8_t *>(s), n));
+}
+
+std::uint64_t Reader::seek(std::uint64_t off, std::ios_base::seekdir dir) {
+ return reader_->seek(off, rust_seek_dir(dir));
+}
+
+} // namespace opendal::details
diff --git a/bindings/cpp/src/details/reader.hpp b/bindings/cpp/src/details/reader.hpp
new file mode 100644
index 000000000..7516e3281
--- /dev/null
+++ b/bindings/cpp/src/details/reader.hpp
@@ -0,0 +1,51 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#pragma once
+
+#include "lib.rs.h"
+
+namespace opendal::details {
+/**
+ * @class Reader
+ * @brief Reader is designed to read data from the operator.
+ * @details It provides basic read and seek operations. If you want to use it
+ * like a stream, you can use `ReaderStream` instead.
+ * @code{.cpp}
+ * opendal::ReaderStream stream(operator.reader("path"));
+ * @endcode
+ */
+class Reader {
+ public:
+ Reader(rust::Box<opendal::ffi::Reader> &&reader)
+ : reader_(std::move(reader)) {}
+
+ Reader(Reader &&) = default;
+
+ ~Reader() = default;
+
+ std::size_t read(void *s, std::size_t n);
+
+ std::uint64_t seek(std::uint64_t off, std::ios_base::seekdir dir);
+
+ private:
+ rust::Box<opendal::ffi::Reader> reader_;
+};
+
+} // namespace opendal::details
diff --git a/bindings/cpp/src/opendal.cpp b/bindings/cpp/src/opendal.cpp
index c886647cb..3b079cd68 100644
--- a/bindings/cpp/src/opendal.cpp
+++ b/bindings/cpp/src/opendal.cpp
@@ -19,155 +19,146 @@
#include "opendal.hpp"
-using namespace opendal;
+#include <memory>
-#define RUST_STR(s) rust::Str(s.data(), s.size())
-#define RUST_STRING(s) rust::String(s.data(), s.size())
+#include "boost/date_time/posix_time/time_parsers.hpp"
+#include "details/lister.hpp"
+#include "details/operator.hpp"
+#include "details/reader.hpp"
-// Operator
+namespace opendal {
-Operator::Operator(std::string_view scheme,
- const std::unordered_map<std::string, std::string> &config) {
- auto rust_map = rust::Vec<ffi::HashMapValue>();
- rust_map.reserve(config.size());
- for (auto &[k, v] : config) {
- rust_map.push_back({RUST_STRING(k), RUST_STRING(v)});
+std::optional<std::string> parse_optional_string(ffi::OptionalString &&s) {
+ if (s.has_value) {
+ return std::string(std::move(s.value));
+ } else {
+ return std::nullopt;
}
+}
- operator_ = opendal::ffi::new_operator(RUST_STR(scheme), rust_map);
+Entry parse_entry(ffi::Entry &&other) {
+ return Entry{
+ .path = std::string(std::move(other.path)),
+ };
}
-bool Operator::available() const { return operator_.has_value(); }
+Metadata parse_meta_data(ffi::Metadata &&meta) {
+ Metadata metadata{
+ .type = static_cast<EntryMode>(meta.mode),
+ .content_length = meta.content_length,
+ .cache_control = parse_optional_string(std::move(meta.cache_control)),
+ .content_disposition =
+ parse_optional_string(std::move(meta.content_disposition)),
+ .content_md5 = parse_optional_string(std::move(meta.content_md5)),
+ .content_type = parse_optional_string(std::move(meta.content_type)),
+ .etag = parse_optional_string(std::move(meta.etag)),
+ };
-// We can't avoid copy, because std::vector hides the internal structure.
-// std::vector doesn't support init from a pointer without copy.
-std::vector<uint8_t> Operator::read(std::string_view path) {
- auto rust_vec = operator_.value()->read(RUST_STR(path));
+ auto last_modified_str = parse_optional_string(std::move(meta.last_modified));
+ if (last_modified_str.has_value()) {
+ metadata.last_modified =
+ boost::posix_time::from_iso_string(last_modified_str.value());
+ }
- return {rust_vec.data(), rust_vec.data() + rust_vec.size()};
+ return metadata;
}
-void Operator::write(std::string_view path, const std::vector<uint8_t> &data) {
- operator_.value()->write(
- RUST_STR(path), rust::Slice<const uint8_t>(data.data(), data.size()));
+Operator::Operator() = default;
+
+Operator::Operator(std::string_view scheme,
+ const std::unordered_map<std::string, std::string> &config) {
+ operator_ = std::make_unique<details::Operator>(scheme, config);
}
-bool Operator::exists(std::string_view path) {
- return operator_.value()->exists(RUST_STR(path));
+Operator::~Operator() = default;
+
+Operator::Operator(Operator &&) = default;
+Operator &Operator::operator=(Operator &&) = default;
+
+bool Operator::available() const { return operator_ != nullptr; }
+
+// We can't avoid copy, because std::vector hides the internal structure.
+// std::vector doesn't support init from a pointer without copy.
+std::string Operator::read(std::string_view path) {
+ return operator_->read(path);
}
-bool Operator::is_exist(std::string_view path) {
- return exists(path);
+void Operator::write(std::string_view path, std::string_view data) {
+ operator_->write(path, data);
}
+bool Operator::exists(std::string_view path) { return operator_->exists(path); }
+
+bool Operator::is_exist(std::string_view path) { return exists(path); }
+
void Operator::create_dir(std::string_view path) {
- operator_.value()->create_dir(RUST_STR(path));
+ operator_->create_dir(path);
}
void Operator::copy(std::string_view src, std::string_view dst) {
- operator_.value()->copy(RUST_STR(src), RUST_STR(dst));
+ operator_->copy(src, dst);
}
void Operator::rename(std::string_view src, std::string_view dst) {
- operator_.value()->rename(RUST_STR(src), RUST_STR(dst));
+ operator_->rename(src, dst);
}
-void Operator::remove(std::string_view path) {
- operator_.value()->remove(RUST_STR(path));
-}
+void Operator::remove(std::string_view path) { operator_->remove(path); }
Metadata Operator::stat(std::string_view path) {
- return {operator_.value()->stat(RUST_STR(path))};
+ return parse_meta_data(operator_->stat(path));
}
std::vector<Entry> Operator::list(std::string_view path) {
- auto rust_vec = operator_.value()->list(RUST_STR(path));
+ auto rust_vec = operator_->list(path);
std::vector<Entry> entries;
entries.reserve(rust_vec.size());
for (auto &&entry : rust_vec) {
- entries.push_back(std::move(entry));
+ entries.emplace_back(parse_entry(std::move(entry)));
}
+
return entries;
}
Lister Operator::lister(std::string_view path) {
- return operator_.value()->lister(RUST_STR(path));
+ return std::make_unique<details::Lister>(operator_->lister(path));
}
Reader Operator::reader(std::string_view path) {
- return operator_.value()->reader(RUST_STR(path));
+ return std::make_unique<details::Reader>(operator_->reader(path));
}
-// Reader
+Lister::Lister(std::unique_ptr<details::Lister> lister)
+ : raw_lister_{std::move(lister)} {};
-std::streamsize Reader::read(void *s, std::streamsize n) {
- auto rust_slice = rust::Slice<uint8_t>(reinterpret_cast<uint8_t *>(s), n);
- auto read_size = raw_reader_->read(rust_slice);
- return read_size;
-}
+Lister::Lister(Lister &&) = default;
-ffi::SeekDir to_rust_seek_dir(std::ios_base::seekdir dir);
-
-std::streampos Reader::seek(std::streamoff off, std::ios_base::seekdir dir) {
- return raw_reader_->seek(off, to_rust_seek_dir(dir));
-}
-
-// Lister
+Lister::~Lister() = default;
std::optional<Entry> Lister::next() {
auto entry = raw_lister_->next();
- if (entry.has_value) {
- return std::move(entry.value);
- } else {
+
+ if (!entry.has_value) {
return std::nullopt;
}
-}
-
-// Metadata
-std::optional<std::string> parse_optional_string(ffi::OptionalString &&s);
-
-Metadata::Metadata(ffi::Metadata &&other) {
- type = static_cast<EntryMode>(other.mode);
- content_length = other.content_length;
- cache_control = parse_optional_string(std::move(other.cache_control));
- content_disposition =
- parse_optional_string(std::move(other.content_disposition));
- content_type = parse_optional_string(std::move(other.content_type));
- content_md5 = parse_optional_string(std::move(other.content_md5));
- etag = parse_optional_string(std::move(other.etag));
- auto last_modified_str =
- parse_optional_string(std::move(other.last_modified));
- if (last_modified_str.has_value()) {
- last_modified =
- boost::posix_time::from_iso_string(last_modified_str.value());
- }
+ return parse_entry(std::move(entry.value));
}
-// Entry
+Reader::Reader(std::unique_ptr<details::Reader> &&reader)
+ : raw_reader_{std::move(reader)} {}
-Entry::Entry(ffi::Entry &&other) : path(std::move(other.path)) {}
+Reader::Reader(Reader &&) = default;
-// helper functions
+Reader::~Reader() = default;
-std::optional<std::string> parse_optional_string(ffi::OptionalString &&s) {
- if (s.has_value) {
- return std::string(std::move(s.value));
- } else {
- return std::nullopt;
- }
+std::streamsize Reader::read(void *s, std::streamsize n) {
+ return raw_reader_->read(s, n);
}
-ffi::SeekDir to_rust_seek_dir(std::ios_base::seekdir dir) {
- switch (dir) {
- case std::ios_base::beg:
- return ffi::SeekDir::Start;
- case std::ios_base::cur:
- return ffi::SeekDir::Current;
- case std::ios_base::end:
- return ffi::SeekDir::End;
- default:
- throw std::runtime_error("invalid seekdir");
- }
-}
\ No newline at end of file
+std::streampos Reader::seek(std::streamoff off, std::ios_base::seekdir dir) {
+ return raw_reader_->seek(off, dir);
+}
+
+} // namespace opendal
diff --git a/bindings/cpp/tests/basic_test.cpp b/bindings/cpp/tests/basic_test.cpp
index 9ffd03df3..c67ceaae1 100644
--- a/bindings/cpp/tests/basic_test.cpp
+++ b/bindings/cpp/tests/basic_test.cpp
@@ -18,7 +18,6 @@
*/
#include <ctime>
-#include <optional>
#include <random>
#include <string>
#include <unordered_map>
@@ -52,7 +51,7 @@ TEST_F(OpendalTest, BasicTest) {
std::string file_path_copied = "test_copied";
std::string file_path_renamed = "test_renamed";
std::string dir_path = "test_dir/";
- std::vector<uint8_t> data = {1, 2, 3, 4, 5};
+ std::string_view data = "abc";
// write
op.write(file_path, data);
@@ -94,7 +93,7 @@ TEST_F(OpendalTest, BasicTest) {
TEST_F(OpendalTest, ReaderTest) {
std::string file_path = "test";
constexpr int size = 2000;
- std::vector<uint8_t> data(size);
+ std::string data(size, 0);
for (auto &d : data) {
d = rng() % 256;
@@ -105,9 +104,10 @@ TEST_F(OpendalTest, ReaderTest) {
// reader
auto reader = op.reader(file_path);
- uint8_t part_data[100];
+ // uint8_t part_data[100];
+ std::string part_data(100, 0);
reader.seek(200, std::ios::cur);
- reader.read(part_data, 100);
+ reader.read(part_data.data(), 100);
EXPECT_EQ(reader.seek(0, std::ios::cur), 300);
for (int i = 0; i < 100; ++i) {
EXPECT_EQ(part_data[i], data[200 + i]);
@@ -115,7 +115,7 @@ TEST_F(OpendalTest, ReaderTest) {
reader.seek(0, std::ios::beg);
// stream
- opendal::ReaderStream stream(std::move(reader));
+ opendal::ReaderStream stream(op.reader(file_path));
auto read_fn = [&](std::size_t to_read, std::streampos expected_tellg) {
std::vector<char> v(to_read);
@@ -133,7 +133,7 @@ TEST_F(OpendalTest, ReaderTest) {
read_fn(1000, 1041);
stream.seekg(0, std::ios::beg);
- std::vector<uint8_t> reader_data(std::istreambuf_iterator<char>{stream}, {});
+ std::string reader_data(std::istreambuf_iterator<char>{stream}, {});
EXPECT_EQ(reader_data, data);
}
@@ -141,9 +141,9 @@ TEST_F(OpendalTest, ListerTest) {
std::string dir_path = "test_dir/";
op.create_dir(dir_path);
auto test1_path = dir_path + "test1";
- op.write(test1_path, {1, 2, 3});
+ op.write(test1_path, "123");
auto test2_path = dir_path + "test2";
- op.write(test2_path, {4, 5, 6});
+ op.write(test2_path, "456");
auto lister = op.lister("test_dir/");
diff --git a/examples/cpp/CMakeLists.txt b/examples/cpp/CMakeLists.txt
index a7fcaec03..4c06bdba0 100644
--- a/examples/cpp/CMakeLists.txt
+++ b/examples/cpp/CMakeLists.txt
@@ -3,14 +3,8 @@ project(opendal-cpp-examples)
set(CMAKE_CXX_STANDARD 17)
-include(FetchContent)
-FetchContent_Declare(
- opendal-cpp
- GIT_REPOSITORY https://github.com/apache/opendal.git
- GIT_TAG v0.52.0
- SOURCE_SUBDIR bindings/cpp
-)
-FetchContent_MakeAvailable(opendal-cpp)
+# use local bindings/cpp directory
+add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../../bindings/cpp opendal_cpp_build)
add_executable(basic-example basic.cpp)
target_link_libraries(basic-example opendal_cpp)
diff --git a/examples/cpp/basic.cpp b/examples/cpp/basic.cpp
index 8fc52f824..2a87aeccf 100644
--- a/examples/cpp/basic.cpp
+++ b/examples/cpp/basic.cpp
@@ -1,11 +1,10 @@
#include "opendal.hpp"
#include <string>
-#include <vector>
#include <iostream>
int main() {
- std::vector<uint8_t> data = {'a', 'b', 'c'};
+ std::string_view data = "abc";
// Init operator
opendal::Operator op = opendal::Operator("memory");
@@ -15,11 +14,17 @@ int main() {
// Read data from operator
auto res = op.read("test"); // res == data
+ std::cout << res << std::endl;
// Using reader
auto reader = op.reader("test");
- opendal::ReaderStream stream(std::move(reader));
- std::string res2;
- stream >> res2; // res2 == "abc"
+ std::string res2(3, 0);
+ reader.read(res2.data(), data.size()); // res2 == "abc"
std::cout << res2 << std::endl;
+
+ // Using reader stream
+ opendal::ReaderStream stream(op.reader("test"));
+ std::string res3;
+ stream >> res3; // res3 == "abc"
+ std::cout << res3 << std::endl;
}