diff --git a/src/html/mod.rs b/src/html/mod.rs
new file mode 100644
index 0000000..33b3ba2
--- /dev/null
+++ b/src/html/mod.rs
@@ -0,0 +1,113 @@
+//! HTML rendering
+use super::*;
+use std::{
+ fmt::{
+ self,
+ Display,
+ },
+};
+
+/// Coerce a `DisplayHtml` value into an opaque implementor of `fmt::Display`.
+#[inline] pub fn display_html<'a, T: DisplayHtml+?Sized>(from: &'a T) -> impl fmt::Display +'a
+{
+ struct Wrap<'a, T: DisplayHtml+?Sized>(&'a T);
+
+ impl<'a,T> fmt::Display for Wrap<'a,T>
+ where T: DisplayHtml+?Sized
+ {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
+ {
+ DisplayHtml::fmt(self.0, f)
+ }
+ }
+
+ Wrap(from)
+}
+
+/// Coerse a `Display` value into a `DisplayHtml` by HTML-escaping its output.
+///
+/// To output raw HTML, see `Safe`.
+#[inline] pub fn escape_html<'a, T: Display+?Sized>(from: &'a T) -> impl DisplayHtml +'a
+{
+ struct Wrap<'a, T: Display+?Sized>(&'a T);
+
+ impl<'a,T> DisplayHtml for Wrap<'a,T>
+ where T: Display +?Sized
+ {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
+ {
+ //TODO: Escape HTML the string
+ }
+ }
+
+ Wrap(from)
+}
+
+/// HTML-safe wrapper around
+#[derive(Debug, PartialEq, Eq)]
+pub struct Safe(T);
+
+impl Safe
+{
+ /// Create a new instance with this value
+ #[inline] pub fn new(value: T) -> Self
+ {
+ Self(value)
+ }
+
+ /// Consume this instance into its inner value
+ pub fn into_inner(self) -> T
+ {
+ self.0
+ }
+
+ /// Gets a reference to the inner value
+ pub fn display(&self) -> &T
+ {
+ &self.0
+ }
+}
+
+impl From for Safe
+{
+ #[inline] fn from(from: T) -> Self
+ {
+ Self(from)
+ }
+}
+
+/// A trait for displaying as html.
+///
+/// Any type implementing `Display` will implement `DisplayHtml` by HTML-escaping the output from it's display formatter.
+/// You can also use `Safe` to render as raw HTML.
+pub trait DisplayHtml
+{
+ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result;
+
+ #[inline] fn to_html(&self) -> String
+ {
+ display_html(self).to_string()
+ }
+}
+impl DisplayHtml for Safe
+{
+ #[inline] fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result
+ {
+ self.0.fmt(fmt)
+ }
+
+ #[inline] fn to_html(&self) -> String
+ {
+ self.0.to_string()
+ }
+}
+
+
+impl DisplayHtml for T
+where T: Display
+{
+ #[inline] fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result
+ {
+ escape_html(self).fmt(fmt)
+ }
+}
diff --git a/src/main.rs b/src/main.rs
index fc6c0c9..4b3c6fb 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -24,6 +24,30 @@ use futures::{
};
use hex_literal::hex;
+macro_rules! cfg_debug {
+ (if {$($if:tt)*} else {$($else:tt)*}) => {
+ {
+ #[cfg(debug_assertions)] {
+ $($if)*
+ }
+ #[cfg(not(debug_assertions))] {
+ $($else)*
+ }
+ }
+ };
+ (if $if:expr) => {
+ {
+ #[cfg(debug_assertions)] $if
+ }
+ };
+ (else $else:expr) => {
+ {
+ #[cfg(not(debug_assertions))] $else
+ }
+ };
+}
+
+
mod ext;
use ext::*;
mod bytes;
@@ -38,6 +62,7 @@ mod identity;
mod post;
mod state;
+mod html;
mod web;
#[tokio::main]
diff --git a/src/web/mod.rs b/src/web/mod.rs
index f6b0549..b7d9015 100644
--- a/src/web/mod.rs
+++ b/src/web/mod.rs
@@ -212,6 +212,16 @@ async fn handle_conn(state: Arc, req: Request) -> Result Result<(), eyre::Report>
{
+ cfg_debug!(if {
+ if &state.config != config::get() {
+ panic!("Our config is not the same as global? This is unsound.");
+ }
+ } else {
+
+ if &state.config != config::get() {
+ warn!("Our config is not the same as global? This is unsound.");
+ }
+ });
let h = {
let state = Arc::new(state);