Dynamically deserialize character data.
This commit is contained in:
parent
44dded7f28
commit
92301fb1d4
|
@ -380,6 +380,15 @@ version = "1.6.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
|
checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "erased-serde"
|
||||||
|
version = "0.3.12"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6ca8b296792113e1500fd935ae487be6e00ce318952a6880555554824d6ebf38"
|
||||||
|
dependencies = [
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "error-chain"
|
name = "error-chain"
|
||||||
version = "0.12.4"
|
version = "0.12.4"
|
||||||
|
@ -1449,6 +1458,7 @@ version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"diesel",
|
"diesel",
|
||||||
"diesel-derive-enum",
|
"diesel-derive-enum",
|
||||||
|
"erased-serde",
|
||||||
"log 0.4.11",
|
"log 0.4.11",
|
||||||
"prost",
|
"prost",
|
||||||
"prost-build",
|
"prost-build",
|
||||||
|
|
|
@ -13,6 +13,7 @@ prost = "0.6"
|
||||||
serde = "1.0"
|
serde = "1.0"
|
||||||
serde_derive = "1.0"
|
serde_derive = "1.0"
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
|
erased-serde = "0.3"
|
||||||
diesel = "1.4"
|
diesel = "1.4"
|
||||||
diesel-derive-enum = { version = "1", features = ["sqlite"] }
|
diesel-derive-enum = { version = "1", features = ["sqlite"] }
|
||||||
thiserror = "1.0"
|
thiserror = "1.0"
|
||||||
|
|
|
@ -1,8 +1,17 @@
|
||||||
|
use crate::errors::Error;
|
||||||
|
use crate::models::proto::cofd::*;
|
||||||
use crate::models::users::User;
|
use crate::models::users::User;
|
||||||
use crate::schema::characters;
|
use crate::schema::characters;
|
||||||
use diesel_derive_enum::DbEnum;
|
use diesel_derive_enum::DbEnum;
|
||||||
use serde_derive::Serialize;
|
use serde_derive::Serialize;
|
||||||
|
|
||||||
|
/// Dynamic character data is an opaque container type that holds
|
||||||
|
/// successfully deserialized character data protobuf object of any
|
||||||
|
/// type. It does not know what kind of type it has. This is a
|
||||||
|
/// semantically more appropriate name for what is returned from the
|
||||||
|
/// dyn_deserialize function.
|
||||||
|
pub(crate) type DynCharacterData = dyn erased_serde::Serialize;
|
||||||
|
|
||||||
/// Control system visibility of a character for a particular user.
|
/// Control system visibility of a character for a particular user.
|
||||||
/// Implemented as a trait because there are multiple character
|
/// Implemented as a trait because there are multiple character
|
||||||
/// structs that need this.
|
/// structs that need this.
|
||||||
|
@ -59,6 +68,32 @@ impl Visibility for Character {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Character {
|
||||||
|
/// Attempt to deserialize the character's data into the given
|
||||||
|
/// type, which must be one of the protobuf types.
|
||||||
|
pub fn try_deserialize<T>(&self) -> Result<T, Error>
|
||||||
|
where
|
||||||
|
T: prost::Message + std::default::Default,
|
||||||
|
{
|
||||||
|
let decoded = T::decode(self.data.as_ref())?;
|
||||||
|
Ok(decoded)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Attempt to deserialize the character's data based on its
|
||||||
|
/// stored type, but return the deserialized protobuf type as a
|
||||||
|
/// trait object. Primarily used for passing character sheets to
|
||||||
|
/// templates or other places (like a REST API).
|
||||||
|
pub fn dyn_deserialize(&self) -> Result<Box<DynCharacterData>, Error> {
|
||||||
|
use CharacterDataType::*;
|
||||||
|
let decoded: Box<dyn erased_serde::Serialize> = match self.data_type {
|
||||||
|
ChroniclesOfDarknessV1 => Box::new(self.try_deserialize::<CofdSheet>()?),
|
||||||
|
ChangelingV1 => Box::new(self.try_deserialize::<ChangelingSheet>()?),
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(decoded)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Debug, Queryable)]
|
#[derive(Serialize, Debug, Queryable)]
|
||||||
pub struct StrippedCharacter {
|
pub struct StrippedCharacter {
|
||||||
pub id: i32,
|
pub id: i32,
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
use crate::db::{Dao, TenebrousDbConn};
|
use crate::db::{Dao, TenebrousDbConn};
|
||||||
use crate::errors::Error;
|
use crate::errors::Error;
|
||||||
use crate::models::characters::Visibility;
|
use crate::models::characters::{CharacterDataType, DynCharacterData, Visibility};
|
||||||
use crate::models::users::User;
|
use crate::models::users::User;
|
||||||
use rocket::request::Form;
|
use rocket::request::Form;
|
||||||
use rocket::response::Redirect;
|
use rocket::response::Redirect;
|
||||||
use rocket_contrib::templates::Template;
|
use rocket_contrib::templates::Template;
|
||||||
|
use serde::Serialize;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
pub(crate) fn routes() -> Vec<rocket::Route> {
|
pub(crate) fn routes() -> Vec<rocket::Route> {
|
||||||
|
@ -23,10 +24,10 @@ struct NewCharacterForm {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize)]
|
#[derive(Serialize)]
|
||||||
struct ViewCharacterTemlate<'a, T> {
|
struct ViewCharacterTemplate<'a> {
|
||||||
pub name: &'a str,
|
pub name: &'a str,
|
||||||
pub username: &'a str,
|
pub username: &'a str,
|
||||||
pub sheet: T,
|
pub sheet: Box<DynCharacterData>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[get("/<username>/<character_id>")]
|
#[get("/<username>/<character_id>")]
|
||||||
|
@ -43,15 +44,10 @@ fn view_character(
|
||||||
.and_then(|c| c.as_visible_for(logged_in_user))
|
.and_then(|c| c.as_visible_for(logged_in_user))
|
||||||
.ok_or(Error::NotFound)?;
|
.ok_or(Error::NotFound)?;
|
||||||
|
|
||||||
//TODO determine sheet type and deserialize based on that.
|
let context = ViewCharacterTemplate {
|
||||||
use crate::models::proto::cofd::CofdSheet;
|
|
||||||
use prost::Message;
|
|
||||||
let sheet = CofdSheet::decode(character.data.as_ref())?;
|
|
||||||
|
|
||||||
let context = ViewCharacterTemlate {
|
|
||||||
name: &character.character_name,
|
name: &character.character_name,
|
||||||
username: &user.username,
|
username: &user.username,
|
||||||
sheet: sheet,
|
sheet: character.dyn_deserialize()?,
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(Template::render("view_character", context))
|
Ok(Template::render("view_character", context))
|
||||||
|
@ -77,7 +73,8 @@ fn create_new_character(
|
||||||
use prost::bytes::BytesMut;
|
use prost::bytes::BytesMut;
|
||||||
use prost::Message;
|
use prost::Message;
|
||||||
|
|
||||||
let new_character = CofdSheet::default();
|
let mut new_character = CofdSheet::default();
|
||||||
|
new_character.strength = 100;
|
||||||
let mut buf = BytesMut::with_capacity(std::mem::size_of_val(&new_character));
|
let mut buf = BytesMut::with_capacity(std::mem::size_of_val(&new_character));
|
||||||
new_character.encode(&mut buf)?;
|
new_character.encode(&mut buf)?;
|
||||||
|
|
||||||
|
@ -85,7 +82,7 @@ fn create_new_character(
|
||||||
user_id: logged_in_user.id,
|
user_id: logged_in_user.id,
|
||||||
viewable: true,
|
viewable: true,
|
||||||
character_name: &form.name,
|
character_name: &form.name,
|
||||||
data_type: std::any::type_name::<CofdSheet>(),
|
data_type: CharacterDataType::ChroniclesOfDarknessV1,
|
||||||
data_version: 1,
|
data_version: 1,
|
||||||
data: &buf,
|
data: &buf,
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue