Crate kodiak_taxonomy
source ·Expand description
Get things organized with this powerful, yet easy to use taxonomy.
This library crate is a building block of the Kodiak project, thus the naming of the crate.
Although, Kodiak has some quite specific requirements for a taxonomy, kodiak-taxonomy
is kept generic,
provides value on its own and might be of interest for other projects as well.
A taxonomy1 is a classification scheme to organize things according to their types. Often, taxonomies offer a strictly hierarchical organization providing a tree-like structure. However, in practice, such taxonomies limit our ability to model our complex reality.
When looking for a powerful taxonomy which overcomes such limitations, kodiak-taxonomy
might be a good fit
for you. So, feel free to use it. If you consider using kodiak-taxonomy
in your project but are missing functionality
or have any other concerns, don’t hesitate to file an issue on Github.
We are looking forward to your feedback.
Getting started
The following example showcases how to use kodiak-taxonomy
. We build a Taxonomy
supporting two processes:
Human Resource Management (HRM) and Configuration Management Database (CMDB). In both processes we
have to organize users and we want to keep the concept of a User identical across the organization.
So, we add User to both processes. This taxonomy would look like:
├── HRM
│ └── User
└── CMDB
├── User (identical to HRM::User)
└── Device
├── Server
└── Client
Here is the code.
use kodiak_taxonomy::{Identity, Taxonomy, TaxonomyError};
// Simplistic type `Class` to store in taxonomy (kodiak-taxonomy supports arbitrary types).
#[derive(Debug)]
struct Class {
name: String,
}
// As a prerequisite for `kodiak-taxonomy` we have to implement the Identity trait for `Class`.
// String implements `Hash` and `Eq` thus it's easy to implement `Identity` on top of it.
impl Identity<String> for Class {
fn id(&self) -> String {
self.name.clone()
}
}
fn main() -> Result<(), TaxonomyError<String>> {
let mut tax: Taxonomy<String, Class> = Taxonomy::new();
// Create various items and store their ids
let hrm = Class{name: "HRM".to_string()};
let hrm_id = hrm.id();
let user = Class{name: "User".to_string()};
let user_id = user.id();
let cmdb = Class{name: "CMDB".to_string()};
let cmdb_id = cmdb.id();
// Add HRM and CMDB as root-node.
tax.add(None, hrm)?
.add(None, cmdb);
// Add User as a sub-node of HRM
tax.add(Some(hrm_id), user);
// Append User as a sub-node of CMDB, we use append() because
// User has been added to taxonomy before.
tax.append(Some(cmdb_id.clone()), user_id);
// Create and add another `Class`. This time we get the id from the taxonomy.
let device = Class{name: "Device".to_string()};
tax.add(Some(cmdb_id), device);
let device_id = tax.last_updated_node().unwrap().to_string();
// Add additional sub-nodes to Devices.
let server = Class{name: "Server".to_string()};
let client = Class{name: "Client".to_string()};
tax.add(Some(device_id.clone()), server)?
.add(Some(device_id), client);
// Traverse the taxonomy and print the classes.
while let Some(class) = tax.traverse() {
println!("{:?}", class);
}
Ok(())
}
The library provides many more functions. Have a look at detailed documentation provided.
TL;DR
Kodiak’s specific requirements regarding its taxonomy and its implementation status:
- The top of the taxonomy allows multiple elements, i.e. users are free to create multiple root-nodes and are not forced to invent a super-node.
- An element can have more than one superordinate element
- Elements might be complemented by arbitrary meta data (still todo: not implemented yet)
- Edges (a tuple of a super and its sub element) might be complemented with arbitrary attributes (still todo: not implemented yet)
Structs
Enums
Traits
K
with K: Hash + Eq
.