Dynamically deserialize character data.
This commit is contained in:
parent
245bd4f2cc
commit
1f07856e66
|
@ -380,6 +380,15 @@ version = "1.6.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
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]]
|
||||
name = "error-chain"
|
||||
version = "0.12.4"
|
||||
|
@ -1449,6 +1458,7 @@ version = "0.1.0"
|
|||
dependencies = [
|
||||
"diesel",
|
||||
"diesel-derive-enum",
|
||||
"erased-serde",
|
||||
"log 0.4.11",
|
||||
"prost",
|
||||
"prost-build",
|
||||
|
|
|
@ -13,6 +13,7 @@ prost = "0.6"
|
|||
serde = "1.0"
|
||||
serde_derive = "1.0"
|
||||
serde_json = "1.0"
|
||||
erased-serde = "0.3"
|
||||
diesel = "1.4"
|
||||
diesel-derive-enum = { version = "1", features = ["sqlite"] }
|
||||
thiserror = "1.0"
|
||||
|
|
|
@ -1,8 +1,17 @@
|
|||
use crate::errors::Error;
|
||||
use crate::models::proto::cofd::*;
|
||||
use crate::models::users::User;
|
||||
use crate::schema::characters;
|
||||
use diesel_derive_enum::DbEnum;
|
||||
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.
|
||||
/// Implemented as a trait because there are multiple character
|
||||
/// 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)]
|
||||
pub struct StrippedCharacter {
|
||||
pub id: i32,
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
use crate::db::{Dao, TenebrousDbConn};
|
||||
use crate::errors::Error;
|
||||
use crate::models::characters::Visibility;
|
||||
use crate::models::characters::{CharacterDataType, DynCharacterData, Visibility};
|
||||
use crate::models::users::User;
|
||||
use rocket::request::Form;
|
||||
use rocket::response::Redirect;
|
||||
use rocket_contrib::templates::Template;
|
||||
use serde::Serialize;
|
||||
use std::collections::HashMap;
|
||||
|
||||
pub(crate) fn routes() -> Vec<rocket::Route> {
|
||||
|
@ -23,10 +24,10 @@ struct NewCharacterForm {
|
|||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct ViewCharacterTemlate<'a, T> {
|
||||
struct ViewCharacterTemplate<'a> {
|
||||
pub name: &'a str,
|
||||
pub username: &'a str,
|
||||
pub sheet: T,
|
||||
pub sheet: Box<DynCharacterData>,
|
||||
}
|
||||
|
||||
#[get("/<username>/<character_id>")]
|
||||
|
@ -43,15 +44,10 @@ fn view_character(
|
|||
.and_then(|c| c.as_visible_for(logged_in_user))
|
||||
.ok_or(Error::NotFound)?;
|
||||
|
||||
//TODO determine sheet type and deserialize based on that.
|
||||
use crate::models::proto::cofd::CofdSheet;
|
||||
use prost::Message;
|
||||
let sheet = CofdSheet::decode(character.data.as_ref())?;
|
||||
|
||||
let context = ViewCharacterTemlate {
|
||||
let context = ViewCharacterTemplate {
|
||||
name: &character.character_name,
|
||||
username: &user.username,
|
||||
sheet: sheet,
|
||||
sheet: character.dyn_deserialize()?,
|
||||
};
|
||||
|
||||
Ok(Template::render("view_character", context))
|
||||
|
@ -77,7 +73,8 @@ fn create_new_character(
|
|||
use prost::bytes::BytesMut;
|
||||
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));
|
||||
new_character.encode(&mut buf)?;
|
||||
|
||||
|
@ -85,7 +82,7 @@ fn create_new_character(
|
|||
user_id: logged_in_user.id,
|
||||
viewable: true,
|
||||
character_name: &form.name,
|
||||
data_type: std::any::type_name::<CofdSheet>(),
|
||||
data_type: CharacterDataType::ChroniclesOfDarknessV1,
|
||||
data_version: 1,
|
||||
data: &buf,
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue