use bumpalo::Bump;
use std::cell::RefCell;
use super::*;
use super::utils::{with_bump_allocator, with_bump_allocator_mut};
pub struct PrintOptions {
pub max_width: u32,
pub indent_width: u8,
pub use_tabs: bool,
pub new_line_text: &'static str,
}
impl PrintOptions {
pub(super) fn to_printer_options(&self) -> PrinterOptions {
PrinterOptions {
indent_width: self.indent_width,
max_width: self.max_width,
#[cfg(feature = "tracing")]
enable_tracing: false,
}
}
pub(super) fn to_write_items_printer_options(&self) -> WriteItemsPrinterOptions {
WriteItemsPrinterOptions {
use_tabs: self.use_tabs,
new_line_text: self.new_line_text,
indent_width: self.indent_width,
}
}
}
pub fn format(get_print_items: impl FnOnce() -> PrintItems, options: PrintOptions) -> String {
increment_formatting_count();
let print_items = get_print_items();
with_bump_allocator_mut(|bump| {
let result = print_with_allocator(bump, &print_items, &options);
if decrement_formatting_count() {
bump.reset();
}
result
})
}
pub fn print(print_items: PrintItems, options: PrintOptions) -> String {
panic_if_not_formatting();
with_bump_allocator(|bump| {
print_with_allocator(bump, &print_items, &options)
})
}
fn print_with_allocator(bump: &Bump, print_items: &PrintItems, options: &PrintOptions) -> String {
let write_items = Printer::new(
bump,
print_items.first_node,
options.to_printer_options(),
).print();
print_write_items(write_items, options.to_write_items_printer_options())
}
#[cfg(feature = "tracing")]
#[derive(serde::Serialize)]
#[serde(rename_all = "camelCase")]
pub struct TracingResult {
pub traces: Vec<Trace>,
pub writer_nodes: Vec<TraceWriterNode>,
pub print_nodes: Vec<TracePrintNode>,
}
#[cfg(feature = "tracing")]
pub fn trace_printing(get_print_items: impl FnOnce() -> PrintItems, options: PrintOptions) -> TracingResult {
increment_formatting_count();
let print_items = get_print_items();
let result = with_bump_allocator_mut(|bump| {
let tracing_result = Printer::new(
bump,
print_items.first_node.clone(),
{
let mut printer_options = options.to_printer_options();
printer_options.enable_tracing = true;
printer_options
},
).print_for_tracing();
let writer_items_printer = WriteItemsPrinter::new(options.to_write_items_printer_options());
let result = TracingResult {
traces: tracing_result.traces,
writer_nodes: tracing_result.writer_nodes.into_iter().map(|node| {
let mut text = String::new();
writer_items_printer.write_to_string(&mut text, node.borrow_item());
TraceWriterNode {
writer_node_id: node.graph_node_id,
previous_node_id: node.borrow_previous().map(|n| n.graph_node_id),
text,
}
}).collect(),
print_nodes: super::get_trace_print_nodes(print_items.first_node.clone()),
};
if decrement_formatting_count() {
bump.reset();
}
result
});
result
}
thread_local! {
static FORMATTING_COUNT: RefCell<u32> = RefCell::new(0);
}
fn increment_formatting_count() {
FORMATTING_COUNT.with(|formatting_count_cell| {
let mut formatting_count = formatting_count_cell.borrow_mut();
*formatting_count += 1;
})
}
fn decrement_formatting_count() -> bool {
FORMATTING_COUNT.with(|formatting_count_cell| {
let mut formatting_count = formatting_count_cell.borrow_mut();
*formatting_count -= 1;
*formatting_count == 0
})
}
fn panic_if_not_formatting() {
FORMATTING_COUNT.with(|formatting_count_cell| {
if *formatting_count_cell.borrow() == 0 {
panic!("dprint_core::formatting::print cannot be called except within the provided closure to dprint_core::formatting::format");
}
})
}