Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Eliminate RenderContextInner #662

Merged
merged 1 commit into from
Jul 19, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
108 changes: 38 additions & 70 deletions src/render.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,19 +33,15 @@ const BLOCK_HELPER_MISSING: &str = "blockHelperMissing";
/// This context stores information of a render and a writer where generated
/// content is written to.
///
#[derive(Clone, Debug)]
pub struct RenderContext<'reg, 'rc> {
inner: Rc<RenderContextInner<'reg, 'rc>>,

#[derive(Clone)]
pub struct RenderContext<'reg: 'rc, 'rc> {
dev_mode_templates: Option<&'rc BTreeMap<String, Cow<'rc, Template>>>,

blocks: VecDeque<BlockContext<'rc>>,

// copy-on-write context
modified_context: Option<Rc<Context>>,
}

#[derive(Clone)]
pub struct RenderContextInner<'reg: 'rc, 'rc> {
partials: BTreeMap<String, &'rc Template>,
partial_block_stack: VecDeque<&'rc Template>,
partial_block_depth: isize,
Expand All @@ -72,7 +68,11 @@ pub struct RenderContextInner<'reg: 'rc, 'rc> {
impl<'reg: 'rc, 'rc> RenderContext<'reg, 'rc> {
/// Create a render context
pub fn new(root_template: Option<&'reg String>) -> RenderContext<'reg, 'rc> {
let inner = Rc::new(RenderContextInner {
let mut blocks = VecDeque::with_capacity(5);
blocks.push_front(BlockContext::new());

let modified_context = None;
RenderContext {
partials: BTreeMap::new(),
partial_block_stack: VecDeque::new(),
partial_block_depth: 0,
Expand All @@ -84,36 +84,12 @@ impl<'reg: 'rc, 'rc> RenderContext<'reg, 'rc> {
content_produced: false,
indent_before_write: false,
indent_string: None,
});

let mut blocks = VecDeque::with_capacity(5);
blocks.push_front(BlockContext::new());

let modified_context = None;
RenderContext {
inner,
blocks,
modified_context,
dev_mode_templates: None,
}
}

pub(crate) fn new_for_block(&self) -> RenderContext<'reg, 'rc> {
let inner = self.inner.clone();

let mut blocks = VecDeque::with_capacity(2);
blocks.push_front(BlockContext::new());

let modified_context = self.modified_context.clone();

RenderContext {
inner,
blocks,
modified_context,
dev_mode_templates: self.dev_mode_templates,
}
}

/// Push a block context into render context stack. This is typically
/// called when you entering a block scope.
pub fn push_block(&mut self, block: BlockContext<'rc>) {
Expand Down Expand Up @@ -141,14 +117,6 @@ impl<'reg: 'rc, 'rc> RenderContext<'reg, 'rc> {
self.blocks.front_mut()
}

fn inner(&self) -> &RenderContextInner<'reg, 'rc> {
self.inner.borrow()
}

fn inner_mut(&mut self) -> &mut RenderContextInner<'reg, 'rc> {
Rc::make_mut(&mut self.inner)
}

/// Get the modified context data if any
pub fn context(&self) -> Option<Rc<Context>> {
self.modified_context.clone()
Expand Down Expand Up @@ -192,45 +160,44 @@ impl<'reg: 'rc, 'rc> RenderContext<'reg, 'rc> {
pub fn get_partial(&self, name: &str) -> Option<&'rc Template> {
if name == partial::PARTIAL_BLOCK {
return self
.inner()
.partial_block_stack
.get(self.inner().partial_block_depth as usize)
.get(self.partial_block_depth as usize)
.copied();
}
self.inner().partials.get(name).copied()
self.partials.get(name).copied()
}

/// Register a partial for this context
pub fn set_partial(&mut self, name: String, partial: &'rc Template) {
self.inner_mut().partials.insert(name, partial);
self.partials.insert(name, partial);
}

pub(crate) fn push_partial_block(&mut self, partial: &'rc Template) {
self.inner_mut().partial_block_stack.push_front(partial);
self.partial_block_stack.push_front(partial);
}

pub(crate) fn pop_partial_block(&mut self) {
self.inner_mut().partial_block_stack.pop_front();
self.partial_block_stack.pop_front();
}

pub(crate) fn inc_partial_block_depth(&mut self) {
self.inner_mut().partial_block_depth += 1;
self.partial_block_depth += 1;
}

pub(crate) fn dec_partial_block_depth(&mut self) {
let depth = &mut self.inner_mut().partial_block_depth;
let depth = &mut self.partial_block_depth;
if *depth > 0 {
*depth -= 1;
}
}

pub(crate) fn set_indent_string(&mut self, indent: Option<Cow<'rc, str>>) {
self.inner_mut().indent_string = indent;
self.indent_string = indent;
}

#[inline]
pub(crate) fn get_indent_string(&self) -> Option<&Cow<'rc, str>> {
self.inner.indent_string.as_ref()
self.indent_string.as_ref()
}

pub(crate) fn get_dev_mode_template(&self, name: &str) -> Option<&'rc Template> {
Expand All @@ -247,7 +214,7 @@ impl<'reg: 'rc, 'rc> RenderContext<'reg, 'rc> {

/// Remove a registered partial
pub fn remove_partial(&mut self, name: &str) {
self.inner_mut().partials.remove(name);
self.partials.remove(name);
}

fn get_local_var(&self, level: usize, name: &str) -> Option<&Json> {
Expand All @@ -258,7 +225,7 @@ impl<'reg: 'rc, 'rc> RenderContext<'reg, 'rc> {

/// Test if given template name is current template.
pub fn is_current_template(&self, p: &str) -> bool {
self.inner().current_template.is_some_and(|s| s == p)
self.current_template.is_some_and(|s| s == p)
}

/// Register a helper in this render context.
Expand All @@ -269,89 +236,90 @@ impl<'reg: 'rc, 'rc> RenderContext<'reg, 'rc> {
name: &str,
def: Box<dyn HelperDef + Send + Sync + 'rc>,
) {
self.inner_mut()
.local_helpers
.insert(name.to_string(), def.into());
self.local_helpers.insert(name.to_string(), def.into());
}

/// Remove a helper from render context
pub fn unregister_local_helper(&mut self, name: &str) {
self.inner_mut().local_helpers.remove(name);
self.local_helpers.remove(name);
}

/// Attempt to get a helper from current render context.
pub fn get_local_helper(&self, name: &str) -> Option<Rc<dyn HelperDef + Send + Sync + 'rc>> {
self.inner().local_helpers.get(name).cloned()
self.local_helpers.get(name).cloned()
}

#[inline]
fn has_local_helper(&self, name: &str) -> bool {
self.inner.local_helpers.contains_key(name)
self.local_helpers.contains_key(name)
}

/// Returns the current template name.
/// Note that the name can be vary from root template when you are rendering
/// from partials.
pub fn get_current_template_name(&self) -> Option<&'rc String> {
self.inner().current_template
self.current_template
}

/// Set the current template name.
pub fn set_current_template_name(&mut self, name: Option<&'rc String>) {
self.inner_mut().current_template = name;
self.current_template = name;
}

/// Get root template name if any.
/// This is the template name that you call `render` from `Handlebars`.
pub fn get_root_template_name(&self) -> Option<&'reg String> {
self.inner().root_template
self.root_template
}

/// Get the escape toggle
pub fn is_disable_escape(&self) -> bool {
self.inner().disable_escape
self.disable_escape
}

/// Set the escape toggle.
/// When toggle is on, `escape_fn` will be called when rendering.
pub fn set_disable_escape(&mut self, disable: bool) {
self.inner_mut().disable_escape = disable;
self.disable_escape = disable;
}

#[inline]
pub fn set_trailing_newline(&mut self, trailing_newline: bool) {
self.inner_mut().trailing_newline = trailing_newline;
self.trailing_newline = trailing_newline;
}

#[inline]
pub fn get_trailine_newline(&self) -> bool {
self.inner().trailing_newline
self.trailing_newline
}

#[inline]
pub fn set_content_produced(&mut self, content_produced: bool) {
self.inner_mut().content_produced = content_produced;
self.content_produced = content_produced;
}

#[inline]
pub fn get_content_produced(&self) -> bool {
self.inner().content_produced
self.content_produced
}

#[inline]
pub fn set_indent_before_write(&mut self, indent_before_write: bool) {
self.inner_mut().indent_before_write = indent_before_write;
self.indent_before_write = indent_before_write;
}

#[inline]
pub fn get_indent_before_write(&self) -> bool {
self.inner().indent_before_write
self.indent_before_write
}
}

impl<'reg, 'rc> fmt::Debug for RenderContextInner<'reg, 'rc> {
impl<'reg, 'rc> fmt::Debug for RenderContext<'reg, 'rc> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
f.debug_struct("RenderContextInner")
.field("dev_mode_templates", &self.dev_mode_templates)
.field("blocks", &self.blocks)
.field("modified_context", &self.modified_context)
.field("partials", &self.partials)
.field("partial_block_stack", &self.partial_block_stack)
.field("partial_block_depth", &self.partial_block_depth)
Expand Down
Loading