UniBox

Universal Box.

Usually, when we want to store different types in a collection we use either one of the following techniques:

  1. An enum to wrap all possible types.
  2. A boxed trait that all types must implement.

Sometimes none of the above techniques are possible. The set of types might be unknown beforehand, for example in a library. And, when we implement a trait, we can only access the methods defined in the trait, not all the methods and properties of the original struct. Furthermore, we are required to use a Box, that means allocating dynamic memory, making no_std applications more complicated.

If you encountered any of these limitations, UniBox is probably a viable solution for your use case.

UniBox can:

UniBox offers two kinds of types:

Usage

Suppose we have 2 different structs with little or nothing in common, like the following User and Server. And we want to store instances of these types in the same collection.

We can use static uniboxes like so:

```rust use unibox::{ Uniboxed, UniBox64 };

[derive(Debug)]

struct BornDate { pub year: u16, pub month: u8, pub day: u8, }

[derive(Debug)]

struct User { pub name: String, pub lastname: String, pub born: BornDate, }

[derive(Debug)]

struct Server { pub domain: String, pub port: u16 }

// We use an ID to identify the different types const USERID : usize = 1111; const SERVERID : usize = 2222;

// If we don't care about identifying the internal type, we can use UniBox64::new() instead let uboxusr = UniBox64::newwithid( User { name: "John".toowned(), lastname: "Dow".toowned(), born: BornDate { year: 1984, month: 12, day: 25 } }, USERID ).expect("Couldn't create UniBox64 for User");

let uboxserver = UniBox64::newwithid( Server { domain: "example.com".toowned(), port: 8080 }, SERVER_ID ).expect("Couldn't create UniBox64 for Server");

// Create a vector with the uniboxes let v = vec!(uboxusr, uboxserver);

for ubox in v.iter() { match ubox.id() { USERID => { // It's a User struct println!("{:#?}", unsafe { ubox.asref::() }); }, SERVERID => { // It's a Server struct println!("{:#?}", unsafe { ubox.asref::() }); }, _ => {} } } ```

The dynamic version, UniBox, works exactly in the same way, the only difference is that it allocates memory to store the type and thus, you don't have to worry about the size.

Features and no_std

This crate is no_std, but it uses the alloc crate to allocate dynamic memory inside UniBox. This is controlled via a feature, enabled by default, named alloc.

If your environment doesn't provide the alloc crate, just disable the default features. If you do so, you won't be able to use UniBox type.