You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

196 lines
4.7 KiB

//! Data structures for the in-memory map.
use super::*;
use std::{
collections::HashMap,
borrow::Cow,
error,
fmt,
};
use generational_arena::{
Arena, Index,
};
use bitflags::bitflags;
use cryptohelpers::{
rsa::{
RsaPublicKey, RsaPrivateKey,
Signature,
},
aes::{self, AesKey,},
sha256::Sha256Hash,
};
use tokio::io::{
AsyncRead, AsyncWrite,
};
/// An absolute (nested) index
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
pub struct AbsoluteIndex(Vec<Index>);
/// Possible value types of the data map
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum Data
{
Byte(u8),
Char(char),
Bool(bool),
/// Signed integer
SI(i64),
/// Unsigned integer
UI(u64),
/// Floating-point integer
FI(f64),
/// A UTF-8 text string
Text(String),
/// A binary blob
Binary(Vec<u8>),
/// A reference index to an item within the same `Datamap` as this one.
RelativeRef(Index),
/// A reference to an item N deep within nested `Map` elements.
///
/// The first `Index` specifies the `Map` data item at the root `Datamap` that contains the next, et cetera. The pointed to value is the last index.
AbsoluteRef(AbsoluteIndex),
/// A list of atoms
List(Vec<Atom>),
/// Another datamap
Map(Datamap),
/// An AES key
AesKey(AesKey),
/// An RSA keypair
RsaKeypair(RsaPrivateKey, RsaPublicKey),
/// An RSA private key
RsaPrivate(RsaPrivateKey),
/// An RSA public key
RsaPublic(RsaPublicKey),
/// A SHA256 hash
Hash(Sha256Hash),
/// A unique ID
Uuid(uuid::Uuid),
/// An RSA signature
Signature(Signature),
/// Nothing
Null,
}
/// An entry that may or may not be encrypted
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum MaybeEncrypted
{
/// This is an encrypted serialized `Data`.
Encrypted(Vec<u8>),
/// An unencrypted `Data`
Unencrypted(Data),
}
submod!(encryption; "impl for `MaybeEncrypted`. \
Other `Data` encryption helpers");
bitflags! {
/// And additional metadata for values
#[derive(Serialize, Deserialize)]
struct Tags: u16
{
/// Default
const NONE = 0;
/// This value should be cloned on write unless specified elsewhere.
const COW = 1<<0;
/// This should not show up in searches.
const HIDDEN = 1<<1;
/// Versioning is enabled for this value.
///
/// When it is deleted, it should instead be moved away into a sperate entry.
const VERSIONED = 1<<2;
}
}
/// Information about a map entry.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct Info
{
alt_name: Option<(String, String)>,
created: u64,
modified: u64,
tags: Tags,
/// Events to be emitted to `State` when this element does something.
///
/// Can be used for monitoring or logging and such.
hooks: event::Hooks,
owner: Option<Vec<user::EntityID>>, //starts as the user that created (i.e. same as `created_by`), or `None` if ownership is disabled
signed: Option<Vec<Signature>>,
perms: user::Permissions,
created_by: user::UserID,
log: Vec<event::InBandEvent>,
}
/// The root data containing map
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Datamap
{
data: Arena<Atom>,
ident: HashMap<Identifier, Index>,
}
impl PartialEq for Datamap
{
fn eq(&self, other: &Self) -> bool
{
self.ident == other.ident && {
for (v1, v2) in self.ident.iter().map(|(_, v)| (self.data.get(*v), other.data.get(*v)))
{
if v1 != v2 {
return false;
}
}
true
}
}
}
/// A value in a datamap, contains the information about the value and the value itself.
///
/// May also contain previous versions of this atom.
///
/// # Note
/// `Atom` boxes most of itself. It's not needed to box `Atom` itself.
// Box these first two together, since they are hueg.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct Atom(Box<(MaybeEncrypted, Info)>, Vec<Atom>);
/// An identifier for an item in a `Datamap`, or an item nested within many `Datamap`s.
#[derive(Debug, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Serialize, Deserialize)]
pub struct Identifier(String);
#[cfg(test)]
mod tests
{
#[test]
fn data_me_sync()
{
let data = super::Data::SI(-120);
let aes = super::aes::AesKey::generate().unwrap();
println!("Data: {:?}", data);
let enc = super::MaybeEncrypted::new_encrypted(data.clone(), &aes).expect("Couldn't encrypt");
println!("M/Enc: {:?}", enc);
let dec = enc.clone().into_unencrypted(Some(&aes)).expect("Couldn't decrypt");
println!("M/Dec: {:?}", dec);
let out = dec.into_data(Some(&aes)).unwrap();
assert_eq!(data, out);
}
}