use core::fmt;
use crate as rune;
use crate::alloc;
use crate::alloc::prelude::*;
use crate::alloc::{HashMap, String, Vec};
use crate::ast;
/// A synthetic identifier which can be used to reference something in storage.
#[derive(TryClone, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[try_clone(copy)]
#[repr(transparent)]
pub struct SyntheticId(usize);
impl fmt::Display for SyntheticId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.fmt(f)
}
}
impl fmt::Debug for SyntheticId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.fmt(f)
}
}
/// The kind of a synthetic token.
#[derive(Debug, Clone, Copy)]
#[non_exhaustive]
pub enum SyntheticKind {
/// A synthetic label.
Label,
/// A synthetic string.
String,
/// A synthetic byte string.
ByteString,
/// A synthetic identifier,
Ident,
/// A synthetic number.
Number,
}
impl fmt::Display for SyntheticKind {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
SyntheticKind::Label => "label".fmt(f),
SyntheticKind::String => "string".fmt(f),
SyntheticKind::ByteString => "byte string".fmt(f),
SyntheticKind::Ident => "identifier".fmt(f),
SyntheticKind::Number => "number".fmt(f),
}
}
}
/// Storage for synthetic language items.
#[derive(Default)]
pub(crate) struct Storage {
/// Stored strings.
strings: Vec<String>,
/// Reverse lookup for existing strings.
strings_rev: HashMap<String, SyntheticId>,
/// Stored byte strings.
byte_strings: Vec<Vec<u8>>,
/// Reverse lookup for existing byte strings.
byte_strings_rev: HashMap<Vec<u8>, SyntheticId>,
/// Numbers stored.
numbers: Vec<ast::Number>,
}
impl Storage {
/// Construct a new number.
///
/// The number will be stored in this storage, and will be synthetic
/// (rather than from the source).
pub(crate) fn insert_number<N>(&mut self, number: N) -> alloc::Result<SyntheticId>
where
ast::Number: From<N>,
{
let id = SyntheticId(self.numbers.len());
self.numbers.try_push(number.into())?;
Ok(id)
}
/// Insert the given text into storage and return its id.
///
/// This will reuse old storage slots that already contains the given
/// string.
pub(crate) fn insert_str(&mut self, string: &str) -> alloc::Result<SyntheticId> {
if let Some(id) = self.strings_rev.get(string).copied() {
return Ok(id);
}
let id = SyntheticId(self.strings.len());
let string = string.try_to_owned()?;
self.strings.try_push(string.try_clone()?)?;
self.strings_rev.try_insert(string, id)?;
Ok(id)
}
/// Insert the given owned string into storage and return its id.
///
/// This will reuse old storage slots that already contains the given
/// string.
pub(crate) fn insert_string(&mut self, string: String) -> alloc::Result<SyntheticId> {
if let Some(id) = self.strings_rev.get(&string).copied() {
return Ok(id);
}
let id = SyntheticId(self.strings.len());
self.strings.try_push(string.try_clone()?)?;
self.strings_rev.try_insert(string, id)?;
Ok(id)
}
/// Insert the given text into storage and return its id.
///
/// This will reuse old storage slots that already contains the given
/// byte string.
pub(crate) fn insert_byte_string(&mut self, bytes: &[u8]) -> alloc::Result<SyntheticId> {
if let Some(id) = self.byte_strings_rev.get(bytes).copied() {
return Ok(id);
}
let id = SyntheticId(self.byte_strings.len());
self.byte_strings.try_push(Vec::try_from(bytes)?)?;
self.byte_strings_rev
.try_insert(Vec::try_from(bytes)?, id)?;
Ok(id)
}
/// Get the content of the string with the specified id.
pub(crate) fn get_string(&self, id: SyntheticId) -> Option<&str> {
self.strings.get(id.0).map(|s| s.as_ref())
}
/// Get the content of the byte string with the specified id.
pub(crate) fn get_byte_string(&self, id: SyntheticId) -> Option<&[u8]> {
self.byte_strings.get(id.0).map(|b| b.as_ref())
}
/// Get the content of the number with the specified id.
pub(crate) fn get_number(&self, id: SyntheticId) -> Option<&ast::Number> {
self.numbers.get(id.0)
}
}