ruststructbsonserde

Rust : Serialize the list of structs and write in a file in BSON format and deserialize back to struct


I am trying to convert list of structs and write in a file in BSON format and deserialize back to struct . I am using

bson = { version="2.6.0" }

crate . I converted my list of structs to Bson , and then tried finding any way to convert the bson to vec[u8] , but didn't find any .

I need to store bson in their binary format only to a specific file.

Here is the code snippet

use std::{fs::File, io::Write};

use serde::{Serialize, Deserialize};

#[derive(Debug,Serialize,Deserialize)]
struct Bison {
    name: String,
    age: u16,
    place: String,
    phone: u16,
}

pub fn check_bson() {
    let mut bisons: Vec<Bison> = Vec::with_capacity(1000);
    for i in 1..1001 {
        bisons.push(Bison {
            name: format!("Name {}", i),
            age: i as u16,
            place: format!("Place {}", i),
            phone: i as u16,
        });
    }

    let mut file = File::create("data.bson").expect("Failed to create file");

    let s = bson::to_bson(&bisons).unwrap();
}

Solution

  • The BSON enum only contains the document tree. In order to get a Vec<u8> you will need to actually encode the Document which can be done like so:

    use bson::{SerializerOptions, Document};
    use serde::{Serialize, Deserialize};
    
    #[derive(Debug,Serialize,Deserialize)]
    struct Bison {
        name: String,
        age: u16,
        place: String,
        phone: u16,
    }
    
    pub fn check_bson() {
        let mut bisons: Vec<Bison> = Vec::with_capacity(1000);
        for i in 1..1001 {
            bisons.push(Bison {
                name: format!("Name {}", i),
                age: i as u16,
                place: format!("Place {}", i),
                phone: i as u16,
            });
        }
    
        let options = SerializerOptions::builder().human_readable(false).build();
        let bson = bson::to_bson_with_options(&bisons, options).unwrap();
        println!("{:?}", bson);
    
        let mut doc = Document::new();
        doc.insert("array".to_string(), bson);
    
        let mut buf = Vec::new();
        doc.to_writer(&mut buf).unwrap();
    
        std::fs::write("data.bson", buf).expect("Failed to create file");
    }
    

    Please note, that we had to give a name to the array (in this case I chose "array"), because an Array itself is a non-Document type and can thus not be used at the top level.

    Alternatively you can use to_vec, but you will also have to consider that the top-level element can not be a BSON Array, so you will have to wrap it like shown below:

    use serde::{Deserialize, Serialize};
    
    #[derive(Debug, Serialize, Deserialize)]
    struct Bison {
        name: String,
        age: u16,
        place: String,
        phone: u16,
    }
    
    #[derive(Debug, Serialize, Deserialize)]
    struct RootElement {
        array: Vec<Bison>,
    }
    
    pub fn check_bson() {
        let mut bisons: Vec<Bison> = Vec::with_capacity(1000);
        for i in 1..1001 {
            bisons.push(Bison {
                name: format!("Name {}", i),
                age: i as u16,
                place: format!("Place {}", i),
                phone: i as u16,
            });
        }
    
        // The root element of a BSON document can not be an array (e.g. a Vec in rust).
        let data = RootElement {
            array: bisons
        };
    
        let buf = bson::to_vec(&data).unwrap();
        std::fs::write("data.bson", buf).expect("Failed to create file");
    }