1 #[cxx::bridge(namespace = "org::blobstore")]
2 mod ffi {
3 // Shared structs with fields visible to both languages.
4 struct BlobMetadata {
5 size: usize,
6 tags: Vec<String>,
7 }
8
9 // Rust types and signatures exposed to C++.
10 extern "Rust" {
11 type MultiBuf;
12
next_chunk(buf: &mut MultiBuf) -> &[u8]13 fn next_chunk(buf: &mut MultiBuf) -> &[u8];
14 }
15
16 // C++ types and signatures exposed to Rust.
17 unsafe extern "C++" {
18 include!("demo/include/blobstore.h");
19
20 type BlobstoreClient;
21
new_blobstore_client() -> UniquePtr<BlobstoreClient>22 fn new_blobstore_client() -> UniquePtr<BlobstoreClient>;
put(&self, parts: &mut MultiBuf) -> u6423 fn put(&self, parts: &mut MultiBuf) -> u64;
tag(&self, blobid: u64, tag: &str)24 fn tag(&self, blobid: u64, tag: &str);
metadata(&self, blobid: u64) -> BlobMetadata25 fn metadata(&self, blobid: u64) -> BlobMetadata;
26 }
27 }
28
29 // An iterator over contiguous chunks of a discontiguous file object.
30 //
31 // Toy implementation uses a Vec<Vec<u8>> but in reality this might be iterating
32 // over some more complex Rust data structure like a rope, or maybe loading
33 // chunks lazily from somewhere.
34 pub struct MultiBuf {
35 chunks: Vec<Vec<u8>>,
36 pos: usize,
37 }
next_chunk(buf: &mut MultiBuf) -> &[u8]38 pub fn next_chunk(buf: &mut MultiBuf) -> &[u8] {
39 let next = buf.chunks.get(buf.pos);
40 buf.pos += 1;
41 next.map_or(&[], Vec::as_slice)
42 }
43
main()44 fn main() {
45 let client = ffi::new_blobstore_client();
46
47 // Upload a blob.
48 let chunks = vec![b"fearless".to_vec(), b"concurrency".to_vec()];
49 let mut buf = MultiBuf { chunks, pos: 0 };
50 let blobid = client.put(&mut buf);
51 println!("blobid = {}", blobid);
52
53 // Add a tag.
54 client.tag(blobid, "rust");
55
56 // Read back the tags.
57 let metadata = client.metadata(blobid);
58 println!("tags = {:?}", metadata.tags);
59 }
60