#![allow(unused)]
use crate::{syntax_pos::Mark, SyntaxContext};
use abi_stable::{
sabi_trait,
std_types::{RBox, RVec},
StableAbi,
};
use anyhow::{Context, Error};
use serde::{de::DeserializeOwned, Serialize};
use std::any::type_name;
#[repr(transparent)]
#[derive(StableAbi)]
pub struct Runtime {
inner: RuntimeImpl_TO<'static, RBox<()>>,
}
#[cfg(feature = "plugin-mode")]
scoped_tls::scoped_thread_local!(
pub(crate) static RT: RuntimeImpl_TO<'static, RBox<()>>
);
#[sabi_trait]
pub trait RuntimeImpl {
fn emit_diagnostic(&self, db: RVec<u8>);
fn fresh_mark(&self, parent: Mark) -> Mark;
fn parent_mark(&self, mar: Mark) -> Mark;
fn is_mark_builtin(&self, mark: Mark) -> bool;
fn set_mark_is_builtin(&self, mark: Mark, is_builtin: bool);
fn is_mark_descendant_of(&self, mark: Mark, ancestor: Mark) -> bool;
fn least_ancestor_of_marks(&self, a: Mark, b: Mark) -> Mark;
fn apply_mark_to_syntax_context_internal(
&self,
ctxt: SyntaxContext,
mark: Mark,
) -> SyntaxContext;
fn remove_mark_of_syntax_context(&self, ctxt: &mut SyntaxContext) -> Mark;
fn outer_mark_of_syntax_context(&self, ctxt: SyntaxContext) -> Mark;
}
#[cfg(feature = "plugin-mode")]
struct PluginEmitter;
#[cfg(feature = "plugin-mode")]
impl crate::errors::Emitter for PluginEmitter {
fn emit(&mut self, db: &crate::errors::DiagnosticBuilder<'_>) {
let bytes: RVec<_> = serialize_for_plugin(&db.diagnostic).unwrap().into();
RT.with(|rt| rt.emit_diagnostic(bytes))
}
}
#[cfg_attr(docsrs, doc(cfg(feature = "plugin-mode")))]
#[cfg(feature = "plugin-mode")]
pub fn with_runtime<F, Ret>(rt: &Runtime, op: F) -> Ret
where
F: FnOnce() -> Ret,
{
use crate::errors::{Handler, HANDLER};
let handler = Handler::with_emitter(true, false, Box::new(PluginEmitter));
RT.set(&rt.inner, || {
HANDLER.set(&handler, || op())
})
}
pub fn serialize_for_plugin<T>(t: &T) -> Result<Vec<u8>, Error>
where
T: Serialize,
{
bincode::serialize(&t)
.with_context(|| format!("failed to serialize `{}` using bincode", type_name::<T>()))
}
pub fn deserialize_for_plugin<T>(bytes: &[u8]) -> Result<T, Error>
where
T: DeserializeOwned,
{
bincode::deserialize(bytes)
.with_context(|| format!("failed to deserialize `{}` using bincode", type_name::<T>()))
}
#[cfg(feature = "plugin-rt")]
struct PluginRt {
name: String,
}
#[cfg(feature = "plugin-rt")]
impl RuntimeImpl for PluginRt {
fn emit_diagnostic(&self, db: RVec<u8>) {
use crate::errors::{Diagnostic, DiagnosticBuilder, HANDLER};
let diagnostic: Diagnostic =
deserialize_for_plugin(db.as_slice()).expect("plugin send invalid diagnostic");
HANDLER.with(|handler| {
DiagnosticBuilder::new_diagnostic(&handler, diagnostic)
.note(&format!(
"this message is generated by plugin `{}`",
&self.name
))
.emit();
});
}
fn fresh_mark(&self, parent: Mark) -> Mark {
Mark::fresh(parent)
}
fn parent_mark(&self, mark: Mark) -> Mark {
mark.parent()
}
fn is_mark_builtin(&self, mark: Mark) -> bool {
mark.is_builtin()
}
fn set_mark_is_builtin(&self, mark: Mark, is_builtin: bool) {
mark.set_is_builtin(is_builtin)
}
fn is_mark_descendant_of(&self, mark: Mark, ancestor: Mark) -> bool {
mark.is_descendant_of(ancestor)
}
fn least_ancestor_of_marks(&self, a: Mark, b: Mark) -> Mark {
Mark::least_ancestor(a, b)
}
fn apply_mark_to_syntax_context_internal(
&self,
ctxt: SyntaxContext,
mark: Mark,
) -> SyntaxContext {
ctxt.apply_mark(mark)
}
fn remove_mark_of_syntax_context(&self, ctxt: &mut SyntaxContext) -> Mark {
ctxt.remove_mark()
}
fn outer_mark_of_syntax_context(&self, ctxt: SyntaxContext) -> Mark {
ctxt.outer()
}
}
#[cfg_attr(docsrs, doc(cfg(feature = "plugin-rt")))]
#[cfg(feature = "plugin-rt")]
pub fn get_runtime_for_plugin(plugin_name: String) -> Runtime {
use abi_stable::erased_types::TD_Opaque;
let rt = PluginRt { name: plugin_name };
let rt: RuntimeImpl_TO<'_, RBox<_>> = RuntimeImpl_TO::from_value(rt, TD_Opaque);
Runtime { inner: rt }
}