# Structuring Data With Serde in Rust

## Introduction

This post details new upgrades in the Rust MongoDB Driver and BSON library to improve our integration with Serde. In the Rust Quick Start blog post, we discussed the trickiness of working with BSON, which has a dynamic schema, in Rust, which uses a static type system. The MongoDB Rust driver and BSON library use Serde to make the conversion between BSON and Rust structs and enums easier. In the 1.2.0 releases of these two libraries, we've included new Serde integration to make working directly with your own Rust data types more seamless and user-friendly.

## Prerequisites

This post assumes that you have a recent version of the Rust toolchain installed (v1.44+), and that you're comfortable with Rust syntax. It also assumes you're familiar with the Rust Serde library.

## Driver Changes

The 1.2.0 Rust driver release introduces a generic type parameter to the Collection type. The generic parameter represents the type of data you want to insert into and find from your MongoDB collection. Any Rust data type that derives/implements the Serde Serialize and Deserialize traits can be used as a type parameter for a Collection.

For example, I'm working with the following struct that defines the schema of the data in my `students` collection:

``` rust
#derive(Serialize, Deserialize)]
struct Student {
    name: String,
    grade: u32,
    test_scores: Vec,
}
```

I can create a generic `Collection` by using the [Database::collection_with_type method and specifying `Student` as the data type I'm working with.

``` rust
let students: Collection = db.collection_with_type("students");
```

Prior to the introduction of the generic `Collection`, the various CRUD `Collection` methods accepted and returned the Document type. This meant I would need to serialize my `Student` structs to `Document`s before inserting them into the students collection. Now, I can insert a `Student` directly into my collection:

``` rust
let student = Student {
    name: "Emily".to_string(),
    grade: 10,
    test_scores: vec and deserialize_with attributes that allow you to specify functions to use for serialization and deserialization on specific fields and variants.

The BSON library now includes a set of functions that implement common strategies for custom serialization and deserialization when working with BSON. You can use these functions by importing them from the `serde_helpers` module in the `bson-rust` crate and using the `serialize_with` and `deserialize_with` attributes. A few of these functions are detailed below.

Some users prefer to represent the object ID field in their data with a hexidecimal string rather than the BSON library ObjectId type:

``` rust
#derive(Serialize, Deserialize)]
    struct Item {
    oid: String,
    // rest of fields
}
```

We've introduced a method for serializing a hex string into an `ObjectId` in the `serde_helpers` module called `serialize_hex_string_as_object_id`. I can annotate my `oid` field with this function using `serialize_with`:

``` rust
#[derive(Serialize, Deserialize)]
struct Item {
    #[serde(serialize_with = "serialize_hex_string_as_object_id")]
    oid: String,
    // rest of fields
}
```

Now, if I serialize an instance of the `Item` struct into BSON, the `oid` field will be represented by an `ObjectId` rather than a `string`.

We've also introduced modules that take care of both serialization and deserialization. For instance, I might want to represent binary data using the [Uuid type in the Rust uuid crate:

``` rust
#derive(Serialize, Deserialize)]
struct Item {
    uuid: Uuid,
    // rest of fields
}
```

Since BSON doesn't have a specific UUID type, I'll need to convert this data into binary if I want to serialize into BSON. I'll also want to convert back to Uuid when deserializing from BSON. The `uuid_as_binary` module in the `serde_helpers` module can take care of both of these conversions. I'll add the following attribute to use this module:

``` rust
#[derive(Serialize, Deserialize)]
struct Item {
    #[serde(with = "uuid_as_binary")]
    uuid: Uuid,
    // rest of fields
}
```

Now, I can work directly with the Uuid type without needing to worry about how to convert it to and from BSON!

The `serde_helpers` module introduces functions for several other common strategies; you can check out the documentation [here.

### Unsigned Integers

The BSON specification defines two integer types: a signed 32 bit integer and a signed 64 bit integer. This can prevent challenges when you attempt to insert data with unsigned integers into your collections.

My `Student` struct from the previous example contains unsigned integers in the `grade `and `test_score` fields. Previous versions of the BSON library would return an error if I attempted to serialize an instance of this struct into `Document`, since there isn't always a clear mapping between unsigned and signed integer types. However, many unsigned integers can fit into signed types! For example, I might want to create the following student:

``` rust
let student = Student {
    name: "Alyson".to_string(),
    grade: 11,
    test_scores: vec. For more details on working with MongoDB in Rust, you can check out the documentation for the Rust driver and BSON library. We also happily accept contributions in the form of Github pull requests - please see the section in our README for info on how to run our tests.

>If you have questions, please head to our developer community website where the MongoDB engineers and the MongoDB community will help you build your next big idea with MongoDB.