当前位置: 首页 > news >正文

网站建设得要素长春火车站附近有什么好玩的地方

网站建设得要素,长春火车站附近有什么好玩的地方,天津市建设 银行网站,网站建设合同贴花算哪一类本示例演示了一个调用blobstore服务的C客户端的Rust应用程序。事实上,我们会看到两个方向的调用:Rust到C以及C到Rust。对于您自己的用例,您可能只需要其中一个方向。 示例中涉及的所有代码都显示在此页面上,但它也以可运行的形式提…

本示例演示了一个调用blobstore服务的C++客户端的Rust应用程序。事实上,我们会看到两个方向的调用:Rust到C++以及C++到Rust。对于您自己的用例,您可能只需要其中一个方向。
示例中涉及的所有代码都显示在此页面上,但它也以可运行的形式提供在demo目录中https://github.com/dtolnay/cxx.要直接尝试,请从该目录运行cargo run。
共享结构、不透明类型和函数已经在上一篇文章中叙述,不清楚的可以先去看一下。

一、创建项目

我们在命令行中创建一个空白的Cargo项目:
cargo new cxx-demo
编辑Cargo.toml文件,添加对cxx的依赖:

[dependencies]
cxx = "1.0"

二、定义语言边界

CXX依赖于对每种语言向另一种语言公开的函数签名的描述。您可以在Rust模块中使用extern块提供此描述,该模块用#[cxx::bridge]属性宏注释。
我们在项目的main.rs文件的顶部添加该内容:

#[cxx::bridge]
mod ffi {
}

该内容将是FFI边界双方需要达成一致的所有内容。

三、从Rust调用C++函数

让我们获取一个C++blobstore客户端的实例,一个在C++中定义的类blobstore client。
我们将把BlobstreClient视为CXX分类中的不透明类型,这样Rust就不需要对其实现做出任何假设,甚至不需要对它的大小或对齐方式做出任何假设。一般来说,C++类型可能有一个与Rust的move语义不兼容的move构造函数,或者可能包含Rust的借用系统无法建模的内部引用。尽管有其他选择,但在FFI边界上不关心任何此类事情的最简单方法是将其视为不透明,不需要了解类型。
不透明类型只能在间接后面操作,如引用&、Rust Box或UniquePtr(std::unique_ptr的Rust绑定)。我们将添加一个函数,通过该函数,C++可以向Rust返回std::unique_ptr。

// src/main.rs#[cxx::bridge]
mod ffi {unsafe extern "C++" {include!("cxx-demo/include/blobstore.h");type BlobstoreClient;fn new_blobstore_client() -> UniquePtr<BlobstoreClient>;}
}fn main() {let client = ffi::new_blobstore_client();
}

即使CXX自动执行静态断言,确保签名与C++中声明的完全匹配,我们仍然需要确保键入的签名是准确的。比如new_blobstore_client函数如果会发生意外(如内存错误)必须用unsafe标记。这次是在一个安全的extern“C++”块中,因为程序员不再需要对签名进行任何安全声明。

四、添加C++代码

在CXX与Cargo的集成中,默认情况下,所有#include路径都以单元包(crate)名称开头。这就是为什么我们看到 include!(“cxx-demowj/include/blobstore.h”) ——我们将把C++头文件放在Rust单元包内的相对路径include/blostore.h处。如果根据Cargo.toml中的name字段,你的crate的名称不是cxx-demo,那么在本教程中,你需要在所有地方使用这个名称来代替cxx-demo。

// include/blobstore.h#pragma once
#include <memory>class BlobstoreClient {
public:BlobstoreClient();
};std::unique_ptr<BlobstoreClient> new_blobstore_client();// src/blobstore.cc#include "cxx-demo/include/blobstore.h"BlobstoreClient::BlobstoreClient() {}std::unique_ptr<BlobstoreClient> new_blobstore_client() {return std::unique_ptr<BlobstoreClient>(new BlobstoreClient());
}

使用std::make_unique也可以,只要你将std(“c++14”)传递给c++编译器,如稍后所述。
include/和src/中的位置并不重要;只要在整个项目中使用正确的路径,就可以将C++代码放置在单元包中的任何其他位置。
请注意,CXX不会查看这些文件中的任何一个。你可以自由地在这里放任意的C++代码, #include你自主的库等等。CXX库所做的就是针对您在头文件中提供的内容发出静态断言。

五、用Cargo编译C++代码

Cargo有一个适合编译非Rust代码的构建脚本功能。
我们需要在Cargo.toml中引入对CXX的C++代码生成器的新的构建时依赖:

# Cargo.toml[dependencies]
cxx = "1.0"[build-dependencies]
cxx-build = "1.0"

然后在Cargo.toml旁边添加一个build.rs构建脚本,以运行cxx构建代码生成器和C++编译器。相关参数是包含cxx::bridge语言边界定义的Rust源文件的路径,以及在Rust crate构建过程中要编译的任何其他C++源文件的道路。

// build.rsfn main() {cxx_build::bridge("src/main.rs").file("src/blobstore.cc").compile("cxx-demo");println!("cargo:rerun-if-changed=src/main.rs");println!("cargo:rerun-if-changed=src/blobstore.cc");println!("cargo:rerun-if-changed=include/blobstore.h");
}

他的build.rs也是您设置C++编译器标志的地方,例如,如果您想从C++14访问std::make_unique。

 cxx_build::bridge("src/main.rs").file("src/blobstore.cc").std("c++14").compile("cxx-demo");

尽管还没有做任何有用的事情,该项目现在应该能够成功构建和运行。命令行输入命令如下:

<cxx-demo路径提示符>  cargo runCompiling cxx-demo v0.1.0Finished dev [unoptimized + debuginfo] target(s) in 0.34sRunning `target/debug/cxx-demo`<cxx-demo路径提示符>

六、从C++调用Rust函数

我们的C++blobstore支持不连续缓冲区上传的put操作。例如,我们可能正在上传一个循环缓冲区的快照,该缓冲区往往由2个部分组成,或者由于其他原因(如绳索数据结构)而分散在内存中的文件片段。
我们将通过在连续的借用块上传递迭代器来表达这一点。这与广泛使用的字节箱的Buf特性的API非常相似。在put过程中,我们将让C++回调到Rust中,以获取上传的连续块(所有块都没有在语言边界上进行复制或分配)。实际上,C++客户端可能包含一些复杂的块批处理或并行上传,所有这些都与之相关。

// src/main.rs#[cxx::bridge]
mod ffi {extern "Rust" {type MultiBuf;fn next_chunk(buf: &mut MultiBuf) -> &[u8];}unsafe extern "C++" {include!("cxx-demo/include/blobstore.h");type BlobstoreClient;fn new_blobstore_client() -> UniquePtr<BlobstoreClient>;fn put(&self, parts: &mut MultiBuf) -> u64;}
}

任何具有self参数的签名(等同C++的this)都被认为是一个方法/非静态成员函数。如果周围的extern块中只有一个类型,则它将是该类型的方法。如果有多个类型,您可以通过在参数列表中编写self:&BlostreClient来区分方法属于哪一个。
像往常一样,现在我们需要提供extern“Rust”块声明的所有内容的Rust定义,以及extern“C++”块宣布的新签名的C++定义。

// src/main.rs// An iterator over contiguous chunks of a discontiguous file object. Toy
// implementation uses a Vec<Vec<u8>> but in reality this might be iterating
// over some more complex Rust data structure like a rope, or maybe loading
// chunks lazily from somewhere.
pub struct MultiBuf {chunks: Vec<Vec<u8>>,pos: usize,
}pub fn next_chunk(buf: &mut MultiBuf) -> &[u8] {let next = buf.chunks.get(buf.pos);buf.pos += 1;next.map_or(&[], Vec::as_slice)
}
// include/blobstore.hstruct MultiBuf;class BlobstoreClient {
public:BlobstoreClient();uint64_t put(MultiBuf &buf) const;
};

在blobstre.cc中,我们可以调用Rust next_chunk函数,该函数通过CXX代码生成器生成的头部文件main.rs.h暴露给C++。在CXX的Cargo集成中,这个生成的头文件有一个包含crate名称、crate中Rust源文件的相对路径和.rs.h扩展名的路径。

// src/blobstore.cc#include "cxx-demo/include/blobstore.h"
#include "cxx-demo/src/main.rs.h"
#include <functional>
#include <string>// Upload a new blob and return a blobid that serves as a handle to the blob.
uint64_t BlobstoreClient::put(MultiBuf &buf) const {// Traverse the caller's chunk iterator.std::string contents;while (true) {auto chunk = next_chunk(buf);if (chunk.size() == 0) {break;}contents.append(reinterpret_cast<const char *>(chunk.data()), chunk.size());}// Pretend we did something useful to persist the data.auto blobid = std::hash<std::string>{}(contents);return blobid;
}

现在可以使用了

// src/main.rsfn main() {let client = ffi::new_blobstore_client();// Upload a blob.let chunks = vec![b"fearless".to_vec(), b"concurrency".to_vec()];let mut buf = MultiBuf { chunks, pos: 0 };let blobid = client.put(&mut buf);println!("blobid = {}", blobid);
}

运行信息如下:

cxx-demo$  cargo runCompiling cxx-demo v0.1.0Finished dev [unoptimized + debuginfo] target(s) in 0.41sRunning `target/debug/cxx-demo`blobid = 9851996977040795552

七、插曲:产生了什么?

对于好奇的人来说,很容易了解CXX为使这些函数调用工作所做的幕后工作。在CXX的正常使用过程中,您不需要这样做,但就本教程而言,这可能具有教育意义。
CXX包含两个代码生成器:一个Rust生成器(即CXX::bridge属性过程宏)和一个C++生成器。
Rust生成的代码
通过cargo-expand可以最容易地查看程序宏的输出。然后运行cargo expand ::ffi宏展开mod ffi模块。

cxx-demo$  cargo install cargo-expand 
cxx-demo$  cargo expand ::ffi

您将看到一些非常令人不快的代码,涉及#[repr(C)]、#[repr©], #[link_name] 和 #[export_name].。

八、C++生成的代码

为了调试方便,cxx_build将所有生成的C++代码链接到Cargo在target/cxxbridge/下的目标目录中。

cxx-demo$  exa -T target/cxxbridge/
target/cxxbridge
├── cxx-demo
│  └── src
│     ├── main.rs.cc -> ../../../debug/build/cxx-demo-11c6f678ce5c3437/out/cxxbridge/sources/cxx-demo/src/main.rs.cc
│     └── main.rs.h -> ../../../debug/build/cxx-demo-11c6f678ce5c3437/out/cxxbridge/include/cxx-demo/src/main.rs.h
└── rust└── cxx.h -> ~/.cargo/registry/src/github.com-1ecc6299db9ec823/cxx-1.0.0/include/cxx.h

在这些文件中,您将看到语言边界中存在的任何CXX Rust类型的声明或模板(如Rust::Slicefor&[T])以及与extern函数对应的extern“C”签名。
如果CXX C++代码生成器更适合您的工作流程,它也可以作为一个独立的可执行文件提供,将生成的代码输出到stdout。

cxx-demo$  cargo install cxxbridge-cmd
cxx-demo$  cxxbridge src/main.rs

九、共享数据结构

到目前为止,上述两个方向的调用只使用了不透明类型,而不是共享结构。
共享结构是数据结构,其完整定义对两种语言都是可见的,从而可以通过值跨语言传递它们。共享结构转换为C++聚合初始化兼容结构,与Rust结构的布局完全匹配。
作为此演示的最后一步,我们将使用共享结构体BlobMetadata在Rust应用程序和C++blobstore客户端之间传递有关blob的元数据。

// src/main.rs#[cxx::bridge]
mod ffi {struct BlobMetadata {size: usize,tags: Vec<String>,}extern "Rust" {// ...}unsafe extern "C++" {// ...fn tag(&self, blobid: u64, tag: &str);fn metadata(&self, blobid: u64) -> BlobMetadata;}
}fn main() {let client = ffi::new_blobstore_client();// Upload a blob.let chunks = vec![b"fearless".to_vec(), b"concurrency".to_vec()];let mut buf = MultiBuf { chunks, pos: 0 };let blobid = client.put(&mut buf);println!("blobid = {}", blobid);// Add a tag.client.tag(blobid, "rust");// Read back the tags.let metadata = client.metadata(blobid);println!("tags = {:?}", metadata.tags);
}
// include/blobstore.h#pragma once
#include "rust/cxx.h"struct MultiBuf;
struct BlobMetadata;class BlobstoreClient {
public:BlobstoreClient();uint64_t put(MultiBuf &buf) const;void tag(uint64_t blobid, rust::Str tag) const;BlobMetadata metadata(uint64_t blobid) const;private:class impl;std::shared_ptr<impl> impl;
};// src/blobstore.cc#include "cxx-demo/include/blobstore.h"
#include "cxx-demo/src/main.rs.h"
#include <algorithm>
#include <functional>
#include <set>
#include <string>
#include <unordered_map>// Toy implementation of an in-memory blobstore.
//
// In reality the implementation of BlobstoreClient could be a large
// complex C++ library.
class BlobstoreClient::impl {friend BlobstoreClient;using Blob = struct {std::string data;std::set<std::string> tags;};std::unordered_map<uint64_t, Blob> blobs;
};BlobstoreClient::BlobstoreClient() : impl(new class BlobstoreClient::impl) {}// Add tag to an existing blob.
void BlobstoreClient::tag(uint64_t blobid, rust::Str tag) const {impl->blobs[blobid].tags.emplace(tag);
}// Retrieve metadata about a blob.
BlobMetadata BlobstoreClient::metadata(uint64_t blobid) const {BlobMetadata metadata{};auto blob = impl->blobs.find(blobid);if (blob != impl->blobs.end()) {metadata.size = blob->second.data.size();std::for_each(blob->second.tags.cbegin(), blob->second.tags.cend(),[&](auto &t) { metadata.tags.emplace_back(t); });}return metadata;
}

运行命令:

cxx-demo$  cargo runRunning `target/debug/cxx-demo`blobid = 9851996977040795552
tags = ["rust"]

现在您已经看到了本教程中涉及的所有代码。它可以在演示目录中以可运行的形式一起使用https://github.com/dtolnay/cxx.您可以直接运行它,而无需从该目录运行cargo run来完成上述步骤。

十、结束语

CXX的主要贡献是它为你提供了Rust与C++的互操作性,在这种互操作性中,你编写的所有Rust端代码看起来都像是在写普通的Rust,而C++端看起来也像是在编写普通的C++。
在文中,您已经看到,所涉及的代码都不像C,也不像通常危险的“FFI胶水”,容易发生泄漏或内存安全缺陷。
由不透明类型、共享类型和关键标准库类型绑定组成的表达系统使API能够在语言边界上进行设计,从而获取接口的正确所有权和借用契约。
CXX发挥了Rust类型系统和C++类型系统的优势以及程序员的直觉。一个在没有Rust背景的C++端或没有C++背景的Rust端工作的人,将能够运用他们对语言开发的所有常见直觉和最佳实践来维护正确的FFI。

http://www.dtcms.com/a/510616.html

相关文章:

  • 十大购物网站常州做网站价位
  • 电子商务网站建设各项费用预算是多少wordpress旺季密码
  • 四川省微信网站建设公静态网站建设背景
  • 设计素材网站排版网站开发工程
  • 网站建设中成本怎么描述官方网站开发方案
  • 东莞营销商城网站建设wordpress适合外贸站
  • 用粉色做网站主题色建设银行网站账户注销
  • 网站域名什么意思seo是做什么工作的
  • 高唐做网站推广广州市南沙区基本建设办公室网站
  • 社区网站设计策划书3000字重庆公司注销的流程及需提供的材料
  • 网站做关键词开封美食网站建设规划
  • 建网站要多少钱 优帮云广东网站建设公司968
  • 哈尔滨市住房与城乡建设局网站绍兴网站建设公司地址
  • 珠海网站开发价格站长工具seo优化
  • 北京网站seo哪家公司好网站开发之ios知识扩展
  • dede网站入侵教程西宁网站建设报价cu君博規范
  • 阜阳网站建设费用企业通讯录
  • 深圳最好用的网站设计阿里巴巴网站导航怎么做
  • 网站title是什么百姓网为什么不能创建地址
  • 怎么建设自己的网站网站建设设计外包公司
  • 5118网站是免费的吗网络服务商
  • 佛山市和城乡建设局网站首页建站极速通
  • 大气手机网站模板免费下载网页界面设计内容
  • 小城镇建设期刊网站广告公关公司
  • 网站程序上传完如何做内网站的宣传栏
  • 福州市交通建设集团有限公司网站现在找个网站这么难的吗
  • 紫色网站模板邯郸网站建设价格
  • 杭州网站外包重庆模板建站公司
  • 版纳网站建设如何做品牌网站设计
  • 网站如何加入百度网盟wordpress页面定制