mirror of
https://github.com/JockeTF/fimfareader.git
synced 2024-11-27 07:28:00 +01:00
Move interner to its own module
This commit is contained in:
parent
2547cf8346
commit
67707830ed
3 changed files with 43 additions and 22 deletions
35
src/archive/interner.rs
Normal file
35
src/archive/interner.rs
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
//! interner module.
|
||||||
|
|
||||||
|
use std::collections::HashSet;
|
||||||
|
use std::sync::RwLock;
|
||||||
|
|
||||||
|
pub struct Interner<T: 'static>(RwLock<HashSet<&'static T>>);
|
||||||
|
|
||||||
|
impl<T> Interner<T>
|
||||||
|
where
|
||||||
|
T: Eq + std::hash::Hash,
|
||||||
|
{
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self(RwLock::new(HashSet::new()))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get(&self, value: &T) -> Option<&'static T> {
|
||||||
|
let store = self.0.read().unwrap();
|
||||||
|
|
||||||
|
store.get(value).map(|value| *value)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set(&self, value: T) -> &'static T {
|
||||||
|
let boxed: Box<T> = Box::new(value);
|
||||||
|
let leaked: &'static T = Box::leak(boxed);
|
||||||
|
let mut store = self.0.write().unwrap();
|
||||||
|
|
||||||
|
store.insert(leaked);
|
||||||
|
|
||||||
|
leaked
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn leak(&self, value: T) -> &'static T {
|
||||||
|
self.get(&value).unwrap_or_else(|| self.set(value))
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
//! Archive module.
|
//! Archive module.
|
||||||
|
|
||||||
mod fetcher;
|
mod fetcher;
|
||||||
|
mod interner;
|
||||||
mod parser;
|
mod parser;
|
||||||
mod story;
|
mod story;
|
||||||
|
|
||||||
|
|
|
@ -1,18 +1,15 @@
|
||||||
//! Story meta.
|
//! Story meta.
|
||||||
|
|
||||||
use std::collections::HashSet;
|
|
||||||
use std::sync::Mutex;
|
|
||||||
|
|
||||||
use chrono::prelude::*;
|
use chrono::prelude::*;
|
||||||
|
use lazy_static::lazy_static;
|
||||||
use serde::de::Error;
|
use serde::de::Error;
|
||||||
use serde::{Deserialize, Deserializer};
|
use serde::{Deserialize, Deserializer};
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
|
|
||||||
use lazy_static::lazy_static;
|
use super::interner::Interner;
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
static ref TAGS: Mutex<HashSet<&'static Tag>> = Mutex::new(HashSet::new());
|
static ref TAGS: Interner<Tag> = Interner::new();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Deserialize)]
|
#[derive(Clone, Debug, Deserialize)]
|
||||||
|
@ -43,7 +40,7 @@ pub struct Story {
|
||||||
pub short_description: String,
|
pub short_description: String,
|
||||||
pub status: Status,
|
pub status: Status,
|
||||||
pub submitted: bool,
|
pub submitted: bool,
|
||||||
#[serde(deserialize_with = "interned_tag")]
|
#[serde(deserialize_with = "tags_as_static")]
|
||||||
pub tags: Vec<&'static Tag>,
|
pub tags: Vec<&'static Tag>,
|
||||||
#[serde(deserialize_with = "null_to_text")]
|
#[serde(deserialize_with = "null_to_text")]
|
||||||
pub title: String,
|
pub title: String,
|
||||||
|
@ -200,25 +197,13 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn interned_tag<'de, D>(d: D) -> Result<Vec<&'static Tag>, D::Error>
|
fn tags_as_static<'de, D>(d: D) -> Result<Vec<&'static Tag>, D::Error>
|
||||||
where
|
where
|
||||||
D: Deserializer<'de>,
|
D: Deserializer<'de>,
|
||||||
{
|
{
|
||||||
let tags = Vec::<Tag>::deserialize(d)?;
|
let tags: Vec<Tag> = Vec::deserialize(d)?;
|
||||||
let mut store = TAGS.lock().unwrap();
|
|
||||||
|
|
||||||
Ok(tags
|
Ok(tags.into_iter().map(|tag| TAGS.leak(tag)).collect())
|
||||||
.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 {
|
impl<'de> Deserialize<'de> for Color {
|
||||||
|
|
Loading…
Reference in a new issue