#[cfg(any(feature = "expression", feature = "known_value"))]
use std::sync::Arc;
use std::sync::{Mutex, Once};
#[cfg(feature = "known_value")]
use bc_components::tags::TAG_KNOWN_VALUE;
use bc_components::tags::*;
#[cfg(feature = "known_value")]
use known_values::{KNOWN_VALUES, KnownValue, KnownValuesStore};
#[cfg(feature = "expression")]
use super::notation::EnvelopeFormatOpts;
#[cfg(feature = "expression")]
use crate::Envelope;
#[cfg(feature = "expression")]
use crate::extension::expressions::{
FunctionsStore, GLOBAL_FUNCTIONS, GLOBAL_PARAMETERS, ParametersStore,
};
#[cfg(any(feature = "expression", feature = "known_value"))]
use crate::string_utils::StringUtils;
#[derive(Clone, Default)]
pub enum FormatContextOpt<'a> {
None,
#[default]
Global,
Custom(&'a FormatContext),
}
impl<'a> From<FormatContextOpt<'a>> for dcbor::TagsStoreOpt<'a> {
fn from(opt: FormatContextOpt<'a>) -> Self {
match opt {
FormatContextOpt::None => dcbor::TagsStoreOpt::None,
FormatContextOpt::Global => dcbor::TagsStoreOpt::Global,
FormatContextOpt::Custom(context) => {
dcbor::TagsStoreOpt::Custom(context.tags())
}
}
}
}
#[derive(Clone)]
pub struct FormatContext {
tags: TagsStore,
#[cfg(feature = "known_value")]
known_values: KnownValuesStore,
#[cfg(feature = "expression")]
functions: FunctionsStore,
#[cfg(feature = "expression")]
parameters: ParametersStore,
}
impl FormatContext {
pub fn new(
tags: Option<&TagsStore>,
#[cfg(feature = "known_value")] known_values: Option<&KnownValuesStore>,
#[cfg(feature = "expression")] functions: Option<&FunctionsStore>,
#[cfg(feature = "expression")] parameters: Option<&ParametersStore>,
) -> Self {
Self {
tags: tags.cloned().unwrap_or_default(),
#[cfg(feature = "known_value")]
known_values: known_values.cloned().unwrap_or_default(),
#[cfg(feature = "expression")]
functions: functions.cloned().unwrap_or_default(),
#[cfg(feature = "expression")]
parameters: parameters.cloned().unwrap_or_default(),
}
}
pub fn tags(&self) -> &TagsStore { &self.tags }
pub fn tags_mut(&mut self) -> &mut TagsStore { &mut self.tags }
#[cfg(feature = "known_value")]
pub fn known_values(&self) -> &KnownValuesStore { &self.known_values }
#[cfg(feature = "expression")]
pub fn functions(&self) -> &FunctionsStore { &self.functions }
#[cfg(feature = "expression")]
pub fn parameters(&self) -> &ParametersStore { &self.parameters }
}
impl TagsStoreTrait for FormatContext {
fn assigned_name_for_tag(&self, tag: &Tag) -> Option<String> {
self.tags.assigned_name_for_tag(tag)
}
fn name_for_tag(&self, tag: &Tag) -> String { self.tags.name_for_tag(tag) }
fn tag_for_name(&self, name: &str) -> Option<Tag> {
self.tags.tag_for_name(name)
}
fn tag_for_value(&self, value: TagValue) -> Option<Tag> {
self.tags.tag_for_value(value)
}
fn summarizer(&self, tag: TagValue) -> Option<&CBORSummarizer> {
self.tags.summarizer(tag)
}
fn name_for_value(&self, value: TagValue) -> String {
self.tags.name_for_value(value)
}
}
impl Default for FormatContext {
fn default() -> Self {
Self::new(
None,
#[cfg(feature = "known_value")]
None,
#[cfg(feature = "expression")]
None,
#[cfg(feature = "expression")]
None,
)
}
}
pub struct LazyFormatContext {
init: Once,
data: Mutex<Option<FormatContext>>,
}
impl LazyFormatContext {
pub fn get(&self) -> std::sync::MutexGuard<'_, Option<FormatContext>> {
self.init.call_once(|| {
bc_components::register_tags();
let tags_binding = dcbor::GLOBAL_TAGS.get();
let tags = tags_binding.as_ref().unwrap();
#[cfg(feature = "known_value")]
let known_values_binding = KNOWN_VALUES.get();
#[cfg(feature = "known_value")]
let known_values = known_values_binding.as_ref().unwrap();
#[cfg(feature = "expression")]
let functions_binding = GLOBAL_FUNCTIONS.get();
#[cfg(feature = "expression")]
let functions = functions_binding.as_ref().unwrap();
#[cfg(feature = "expression")]
let parameters_binding = GLOBAL_PARAMETERS.get();
#[cfg(feature = "expression")]
let parameters = parameters_binding.as_ref().unwrap();
let context = FormatContext::new(
Some(tags),
#[cfg(feature = "known_value")]
Some(known_values),
#[cfg(feature = "expression")]
Some(functions),
#[cfg(feature = "expression")]
Some(parameters),
);
*self.data.lock().unwrap() = Some(context);
});
self.data.lock().unwrap()
}
}
pub static GLOBAL_FORMAT_CONTEXT: LazyFormatContext =
LazyFormatContext { init: Once::new(), data: Mutex::new(None) };
#[macro_export]
macro_rules! with_format_context {
($action:expr) => {{
let binding = $crate::GLOBAL_FORMAT_CONTEXT.get();
let context = &*binding.as_ref().unwrap();
#[allow(clippy::redundant_closure_call)]
$action(context)
}};
}
#[macro_export]
macro_rules! with_format_context_mut {
($action:expr) => {{
let mut binding = $crate::GLOBAL_FORMAT_CONTEXT.get();
let context = binding.as_mut().unwrap();
#[allow(clippy::redundant_closure_call)]
$action(context)
}};
}
pub fn register_tags_in(context: &mut FormatContext) {
bc_components::register_tags_in(context.tags_mut());
#[cfg(feature = "known_value")]
{
let known_values = context.known_values().clone();
context.tags_mut().set_summarizer(
TAG_KNOWN_VALUE,
Arc::new(move |untagged_cbor: CBOR, _flat: bool| {
Ok(known_values
.name(KnownValue::from_untagged_cbor(untagged_cbor)?)
.flanked_by("'", "'"))
}),
);
}
#[cfg(feature = "expression")]
{
use crate::extension::expressions::{
Function, FunctionsStore, Parameter, ParametersStore,
};
let functions = context.functions().clone();
context.tags_mut().set_summarizer(
TAG_FUNCTION,
Arc::new(move |untagged_cbor: CBOR, _flat: bool| {
let f = Function::from_untagged_cbor(untagged_cbor)?;
Ok(FunctionsStore::name_for_function(&f, Some(&functions))
.flanked_by("«", "»"))
}),
);
let parameters = context.parameters().clone();
context.tags_mut().set_summarizer(
TAG_PARAMETER,
Arc::new(move |untagged_cbor: CBOR, _flat: bool| {
let p = Parameter::from_untagged_cbor(untagged_cbor)?;
Ok(ParametersStore::name_for_parameter(&p, Some(¶meters))
.flanked_by("❰", "❱"))
}),
);
let cloned_context = context.clone();
context.tags_mut().set_summarizer(
TAG_REQUEST,
Arc::new(move |untagged_cbor: CBOR, flat: bool| {
Ok(Envelope::new(untagged_cbor)
.format_opt(
&EnvelopeFormatOpts::default()
.flat(flat)
.context(FormatContextOpt::Custom(&cloned_context)),
)
.flanked_by("request(", ")"))
}),
);
let cloned_context = context.clone();
context.tags_mut().set_summarizer(
TAG_RESPONSE,
Arc::new(move |untagged_cbor: CBOR, flat: bool| {
Ok(Envelope::new(untagged_cbor)
.format_opt(
&EnvelopeFormatOpts::default()
.flat(flat)
.context(FormatContextOpt::Custom(&cloned_context)),
)
.flanked_by("response(", ")"))
}),
);
let cloned_context = context.clone();
context.tags_mut().set_summarizer(
TAG_EVENT,
Arc::new(move |untagged_cbor: CBOR, flat: bool| {
Ok(Envelope::new(untagged_cbor)
.format_opt(
&EnvelopeFormatOpts::default()
.flat(flat)
.context(FormatContextOpt::Custom(&cloned_context)),
)
.flanked_by("event(", ")"))
}),
);
}
}
pub fn register_tags() {
with_format_context_mut!(|context: &mut FormatContext| {
register_tags_in(context);
});
}