Intern tag structs to save memory

This commit is contained in:
Joakim Soderlund 2020-05-22 00:24:10 +02:00
parent 3b1d99e14c
commit 2547cf8346
3 changed files with 38 additions and 2 deletions

1
Cargo.lock generated
View file

@ -124,6 +124,7 @@ version = "0.1.0"
dependencies = [
"chrono 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
"hex 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rayon 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.110 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.53 (registry+https://github.com/rust-lang/crates.io-index)",

View file

@ -27,6 +27,9 @@ features = ["serde"]
[dependencies.hex]
version = "*"
[dependencies.lazy_static]
version = "*"
[dependencies.rayon]
version = "*"

View file

@ -1,10 +1,20 @@
//! Story meta.
use std::collections::HashSet;
use std::sync::Mutex;
use chrono::prelude::*;
use serde::de::Error;
use serde::{Deserialize, Deserializer};
use serde_json::Value;
use lazy_static::lazy_static;
lazy_static! {
static ref TAGS: Mutex<HashSet<&'static Tag>> = Mutex::new(HashSet::new());
}
#[derive(Clone, Debug, Deserialize)]
pub struct Story {
pub archive: Archive,
@ -33,7 +43,8 @@ pub struct Story {
pub short_description: String,
pub status: Status,
pub submitted: bool,
pub tags: Vec<Tag>,
#[serde(deserialize_with = "interned_tag")]
pub tags: Vec<&'static Tag>,
#[serde(deserialize_with = "null_to_text")]
pub title: String,
pub total_num_views: i32,
@ -143,7 +154,7 @@ pub enum Status {
Visible,
}
#[derive(Clone, Debug, Deserialize)]
#[derive(Clone, Debug, Hash, PartialEq, Eq, Deserialize)]
pub struct Tag {
pub id: i64,
pub name: String,
@ -189,6 +200,27 @@ where
}
}
fn interned_tag<'de, D>(d: D) -> Result<Vec<&'static Tag>, D::Error>
where
D: Deserializer<'de>,
{
let tags = Vec::<Tag>::deserialize(d)?;
let mut store = TAGS.lock().unwrap();
Ok(tags
.into_iter()
.map(|tag| match store.get(&tag) {
Some(tag) => tag,
None => {
let boxed: Box<Tag> = Box::new(tag);
let leaked: &'static Tag = Box::leak(boxed);
store.insert(leaked);
leaked
}
})
.collect())
}
impl<'de> Deserialize<'de> for Color {
fn deserialize<D>(d: D) -> Result<Color, D::Error>
where