#![feature(const_fn_transmute)]
use std::{borrow::Borrow, ops::Deref};
use std::convert::TryFrom;
pub type JSParseError = boa::syntax::parser::ParseError;
#[repr(transparent)]
pub struct JSStr {
data: str,
}
pub struct JSString {
code: String,
}
pub trait JSTemplate {
fn render_template(&self) -> JSString;
}
impl JSStr {
pub fn new(js: &str) -> Result<&Self, JSParseError> {
let _ = boa::parse(js, false)?;
Ok(unsafe { JSStr::new_unchecked(js) })
}
pub const unsafe fn new_unchecked(js: &str) -> &Self {
std::mem::transmute(js)
}
pub fn as_str(&self) -> &str {
&self.data
}
}
impl<'a> TryFrom<&'a str> for &'a JSStr {
type Error = JSParseError;
fn try_from(value: &'a str) -> Result<Self, Self::Error> {
JSStr::new(value)
}
}
impl AsRef<JSStr> for JSStr {
fn as_ref(&self) -> &JSStr {
self
}
}
impl AsRef<str> for JSStr {
fn as_ref(&self) -> &str {
&self.data
}
}
impl<'a> Into<&'a str> for &'a JSStr {
fn into(self) -> &'a str {
&self.data
}
}
impl ToOwned for JSStr {
type Owned = JSString;
fn to_owned(&self) -> Self::Owned {
unsafe {
JSString::new_unchecked(self.as_str().to_owned())
}
}
}
impl JSString {
pub fn new(code: String) -> Result<Self, JSParseError> {
let _ = JSStr::new(&code)?;
Ok(JSString{ code })
}
pub unsafe fn new_unchecked(code: String) -> Self {
JSString{ code }
}
pub fn into_string(self) -> String {
self.code
}
}
impl TryFrom<String> for JSString {
type Error = JSParseError;
fn try_from(value: String) -> Result<Self, Self::Error> {
JSString::new(value)
}
}
impl Into<String> for JSString {
fn into(self) -> String {
self.code
}
}
impl Borrow<JSStr> for JSString {
fn borrow(&self) -> &JSStr {
unsafe { JSStr::new_unchecked(&self.code) }
}
}
impl AsRef<JSStr> for JSString {
fn as_ref(&self) -> &JSStr {
self.borrow()
}
}
impl Deref for JSString {
type Target = JSStr;
fn deref(&self) -> &Self::Target {
unsafe { JSStr::new_unchecked(&self.code) }
}
}