2023-10-27 18:43:06 +00:00
|
|
|
use std::collections::HashMap;
|
2023-10-29 22:35:42 +00:00
|
|
|
use std::marker::PhantomData;
|
2023-10-30 01:19:30 +00:00
|
|
|
use std::sync::Arc;
|
|
|
|
use std::sync::Mutex;
|
2023-10-27 18:43:06 +00:00
|
|
|
|
2023-10-30 00:30:09 +00:00
|
|
|
// use super::ast_node::IntoIAstNode;
|
2023-10-29 18:14:10 +00:00
|
|
|
use crate::error::CustomError;
|
2023-10-29 16:31:48 +00:00
|
|
|
use organic::types::Element;
|
2023-10-29 16:06:40 +00:00
|
|
|
use organic::types::Object;
|
|
|
|
|
2023-10-29 17:51:32 +00:00
|
|
|
use super::ast_node::IAstNode;
|
2023-10-30 01:33:43 +00:00
|
|
|
use super::ast_node::IntoIAstNode;
|
2023-10-30 01:19:30 +00:00
|
|
|
use super::RefRegistry;
|
2023-10-29 17:51:32 +00:00
|
|
|
|
2023-10-27 18:43:06 +00:00
|
|
|
type IdCounter = u16;
|
|
|
|
|
2023-10-29 21:29:16 +00:00
|
|
|
pub(crate) struct Registry<'orig, 'parse> {
|
2023-10-27 18:43:06 +00:00
|
|
|
id_counter: IdCounter,
|
2023-10-27 18:54:54 +00:00
|
|
|
targets: HashMap<&'parse str, String>,
|
2023-10-29 22:35:42 +00:00
|
|
|
footnote_ids: Vec<(Option<&'parse str>, Vec<IAstNode>)>,
|
|
|
|
_phantom: PhantomData<&'orig ()>,
|
2023-10-27 18:43:06 +00:00
|
|
|
}
|
|
|
|
|
2023-10-29 21:29:16 +00:00
|
|
|
impl<'orig, 'parse> Registry<'orig, 'parse> {
|
|
|
|
pub(crate) fn new() -> Registry<'orig, 'parse> {
|
2023-10-27 18:43:06 +00:00
|
|
|
Registry {
|
|
|
|
id_counter: 0,
|
|
|
|
targets: HashMap::new(),
|
2023-10-29 16:06:40 +00:00
|
|
|
footnote_ids: Vec::new(),
|
2023-10-29 22:35:42 +00:00
|
|
|
_phantom: PhantomData,
|
2023-10-27 18:43:06 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-10-29 21:29:16 +00:00
|
|
|
pub(crate) fn get_target<'reg>(&'reg mut self, body: &'parse str) -> &'reg String {
|
2023-10-27 18:43:06 +00:00
|
|
|
self.targets.entry(body).or_insert_with(|| {
|
|
|
|
self.id_counter += 1;
|
|
|
|
format!("target_{}", self.id_counter)
|
|
|
|
})
|
|
|
|
}
|
2023-10-29 16:06:40 +00:00
|
|
|
|
2023-10-29 19:36:15 +00:00
|
|
|
pub(crate) fn get_footnote_ids(&self) -> impl Iterator<Item = (usize, &Vec<IAstNode>)> {
|
2023-10-29 22:35:42 +00:00
|
|
|
self.footnote_ids
|
|
|
|
.iter()
|
|
|
|
.map(|(_label, definition)| definition)
|
|
|
|
.enumerate()
|
2023-10-29 19:36:15 +00:00
|
|
|
}
|
2023-10-30 01:19:30 +00:00
|
|
|
}
|
2023-10-29 19:36:15 +00:00
|
|
|
|
2023-10-30 01:19:30 +00:00
|
|
|
/// Get a 0-indexed ID for a footnote.
|
|
|
|
///
|
|
|
|
/// This needs to be incremented to be 1-indexed for render.
|
|
|
|
pub(crate) async fn get_footnote_reference_id<'orig, 'parse>(
|
|
|
|
registry: RefRegistry<'orig, 'parse>,
|
|
|
|
label: Option<&'parse str>,
|
|
|
|
definition: &'orig Vec<Object<'parse>>,
|
|
|
|
) -> Result<usize, CustomError> {
|
|
|
|
if let None = label {
|
|
|
|
// If it has no label then it must always get a new ID.
|
|
|
|
let contents = convert_reference_contents(registry.clone(), definition).await?;
|
|
|
|
let pos = {
|
|
|
|
let mut registry = registry.lock().unwrap();
|
|
|
|
registry.footnote_ids.push((None, contents));
|
|
|
|
registry.footnote_ids.len() - 1
|
|
|
|
};
|
|
|
|
return Ok(pos);
|
|
|
|
}
|
2023-10-29 16:06:40 +00:00
|
|
|
|
2023-10-30 01:19:30 +00:00
|
|
|
let existing_index = registry
|
|
|
|
.lock()
|
|
|
|
.unwrap()
|
|
|
|
.footnote_ids
|
|
|
|
.iter()
|
|
|
|
.position(|(id, _definition)| *id == label);
|
|
|
|
if let Some(existing_id) = existing_index {
|
|
|
|
if !definition.is_empty() {
|
|
|
|
let contents = convert_reference_contents(registry.clone(), definition).await?;
|
|
|
|
let mut registry = registry.lock().unwrap();
|
|
|
|
let entry = registry
|
|
|
|
.footnote_ids
|
|
|
|
.get_mut(existing_id)
|
|
|
|
.expect("If-statement proves this to be Some.");
|
|
|
|
entry.1 = contents;
|
2023-10-29 16:06:40 +00:00
|
|
|
}
|
2023-10-30 01:19:30 +00:00
|
|
|
Ok(existing_id)
|
|
|
|
} else {
|
|
|
|
let contents = convert_reference_contents(registry.clone(), definition).await?;
|
|
|
|
let pos = {
|
|
|
|
let mut registry = registry.lock().unwrap();
|
|
|
|
registry.footnote_ids.push((label, contents));
|
|
|
|
registry.footnote_ids.len() - 1
|
|
|
|
};
|
|
|
|
Ok(pos)
|
2023-10-29 16:06:40 +00:00
|
|
|
}
|
2023-10-30 01:19:30 +00:00
|
|
|
}
|
2023-10-29 16:31:48 +00:00
|
|
|
|
2023-10-30 01:19:30 +00:00
|
|
|
/// Update the definition to a footnote but do not mark it as referenced.
|
|
|
|
pub(crate) async fn register_footnote_definition<'orig, 'parse>(
|
|
|
|
registry: RefRegistry<'orig, 'parse>,
|
|
|
|
label: &'parse str,
|
|
|
|
definition: &'orig Vec<Element<'parse>>,
|
|
|
|
) -> Result<(), CustomError> {
|
2023-10-30 01:44:15 +00:00
|
|
|
let has_existing: bool = {
|
|
|
|
let mut registry = registry.lock().unwrap();
|
|
|
|
registry
|
|
|
|
.footnote_ids
|
|
|
|
.iter_mut()
|
|
|
|
.any(|(id, _definition)| *id == Some(label))
|
|
|
|
};
|
|
|
|
if !has_existing {
|
|
|
|
return Ok(());
|
|
|
|
}
|
2023-10-30 01:19:30 +00:00
|
|
|
let contents = convert_definition_contents(registry.clone(), definition).await?;
|
|
|
|
let mut registry = registry.lock().unwrap();
|
|
|
|
if let Some((_existing_id, existing_definition)) = registry
|
|
|
|
.footnote_ids
|
|
|
|
.iter_mut()
|
|
|
|
.find(|(id, _definition)| *id == Some(label))
|
|
|
|
{
|
|
|
|
*existing_definition = contents;
|
2023-10-29 16:31:48 +00:00
|
|
|
}
|
2023-10-30 01:19:30 +00:00
|
|
|
Ok(())
|
2023-10-29 16:31:48 +00:00
|
|
|
}
|
|
|
|
|
2023-10-30 01:19:30 +00:00
|
|
|
async fn convert_reference_contents<'orig, 'parse>(
|
|
|
|
registry: RefRegistry<'orig, 'parse>,
|
2023-10-29 21:29:16 +00:00
|
|
|
contents: &'orig Vec<Object<'parse>>,
|
2023-10-29 18:14:10 +00:00
|
|
|
) -> Result<Vec<IAstNode>, CustomError> {
|
|
|
|
let contents = {
|
|
|
|
let mut ret = Vec::new();
|
|
|
|
for obj in contents.iter() {
|
2023-10-30 01:33:43 +00:00
|
|
|
ret.push(obj.into_ast_node(registry.clone()).await?);
|
2023-10-29 18:14:10 +00:00
|
|
|
}
|
|
|
|
ret
|
|
|
|
};
|
|
|
|
|
|
|
|
Ok(contents)
|
|
|
|
}
|
|
|
|
|
2023-10-30 01:19:30 +00:00
|
|
|
async fn convert_definition_contents<'orig, 'parse>(
|
|
|
|
registry: RefRegistry<'orig, 'parse>,
|
2023-10-29 21:29:16 +00:00
|
|
|
contents: &'orig Vec<Element<'parse>>,
|
2023-10-29 18:14:10 +00:00
|
|
|
) -> Result<Vec<IAstNode>, CustomError> {
|
|
|
|
let contents = {
|
|
|
|
let mut ret = Vec::new();
|
|
|
|
for obj in contents.iter() {
|
2023-10-30 01:33:43 +00:00
|
|
|
ret.push(obj.into_ast_node(registry.clone()).await?);
|
2023-10-29 18:14:10 +00:00
|
|
|
}
|
|
|
|
ret
|
|
|
|
};
|
|
|
|
|
|
|
|
Ok(contents)
|
2023-10-27 18:43:06 +00:00
|
|
|
}
|