Refactor: Use trait constraints instead of a trait object for our assets cache.

This commit is contained in:
Jeremy Wall 2019-05-28 18:24:02 -05:00
parent fc9595ab38
commit 1589aaf7d7
4 changed files with 56 additions and 33 deletions

View File

@ -19,6 +19,7 @@ use std::error::Error;
use std::str::Chars;
use crate::ast::*;
use crate::build::assets;
use crate::build::{FileBuilder, Val};
use crate::error;
@ -85,13 +86,19 @@ impl<V: Into<String> + Clone> FormatRenderer for SimpleFormatter<V> {
}
}
pub struct ExpressionFormatter<'a> {
pub struct ExpressionFormatter<'a, C>
where
C: assets::Cache,
{
tmpl: String,
builder: RefCell<FileBuilder<'a>>,
builder: RefCell<FileBuilder<'a, C>>,
}
impl<'a> ExpressionFormatter<'a> {
pub fn new<S: Into<String>>(tmpl: S, builder: FileBuilder<'a>) -> Self {
impl<'a, C> ExpressionFormatter<'a, C>
where
C: assets::Cache,
{
pub fn new<S: Into<String>>(tmpl: S, builder: FileBuilder<'a, C>) -> Self {
ExpressionFormatter {
tmpl: tmpl.into(),
builder: RefCell::new(builder),
@ -100,7 +107,7 @@ impl<'a> ExpressionFormatter<'a> {
fn consume_expr(
&self,
builder: &mut FileBuilder,
builder: &mut FileBuilder<'a, C>,
iter: &mut Chars,
pos: &Position,
) -> Result<Val, Box<dyn Error>> {
@ -176,7 +183,10 @@ impl<'a> ExpressionFormatter<'a> {
}
}
impl<'a> FormatRenderer for ExpressionFormatter<'a> {
impl<'a, C> FormatRenderer for ExpressionFormatter<'a, C>
where
C: assets::Cache,
{
fn render(&self, pos: &Position) -> Result<String, Box<dyn Error>> {
let mut buf = String::new();
let mut should_escape = false;

View File

@ -53,11 +53,14 @@ enum ProcessingOpType {
impl FuncDef {
/// Expands a ucg function using the given arguments into a new Val.
pub fn eval(
pub fn eval<C>(
&self,
parent_builder: &FileBuilder,
parent_builder: &FileBuilder<C>,
mut args: Vec<Rc<Val>>,
) -> Result<Rc<Val>, Box<dyn Error>> {
) -> Result<Rc<Val>, Box<dyn Error>>
where
C: assets::Cache,
{
// Error conditions. If the args don't match the length and types of the argdefs then this is
// func call error.
if args.len() > self.argdefs.len() {
@ -98,7 +101,10 @@ pub struct AssertCollector {
}
/// Builder handles building ucg code for a single file.
pub struct FileBuilder<'a> {
pub struct FileBuilder<'a, C>
where
C: assets::Cache,
{
working_dir: PathBuf,
std: Rc<HashMap<String, &'static str>>,
import_path: &'a Vec<PathBuf>,
@ -117,7 +123,7 @@ pub struct FileBuilder<'a> {
// are keyed by the canonicalized import path. This acts as a cache
// so multiple imports of the same file don't have to be parsed
// multiple times.
assets: Rc<RefCell<assets::Cache>>,
assets: Rc<RefCell<C>>,
pub is_module: bool,
pub last: Option<Rc<Val>>,
pub out_lock: Option<(String, Rc<Val>)>,
@ -141,12 +147,15 @@ macro_rules! eval_binary_expr {
};
}
impl<'a> FileBuilder<'a> {
impl<'a, C> FileBuilder<'a, C>
where
C: assets::Cache,
{
/// Constructs a new Builder.
pub fn new<P: Into<PathBuf>>(
working_dir: P,
import_paths: &'a Vec<PathBuf>,
cache: Rc<RefCell<assets::Cache>>,
cache: Rc<RefCell<C>>,
) -> Self {
let env_vars: Vec<(String, String)> = env::vars().collect();
let scope = scope::Scope::new(Rc::new(Val::Env(env_vars)));

View File

@ -11,6 +11,7 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use super::assets;
use super::assets::MemoryCache;
use super::{FileBuilder, SelectDef, Val};
use crate::ast::*;
@ -19,7 +20,10 @@ use std;
use std::cell::RefCell;
use std::rc::Rc;
fn test_expr_to_val(mut cases: Vec<(Expression, Val)>, b: FileBuilder) {
fn test_expr_to_val<'a, C: assets::Cache>(
mut cases: Vec<(Expression, Val)>,
b: FileBuilder<'a, C>,
) {
for tpl in cases.drain(0..) {
assert_eq!(
b.eval_expr(&tpl.0, &b.scope.spawn_child()).unwrap(),

View File

@ -93,13 +93,13 @@ fn run_converter(c: &traits::Converter, v: Rc<Val>, f: Option<&str>) -> traits::
c.convert(v, file.as_mut())
}
fn build_file<'a>(
fn build_file<'a, C: Cache>(
file: &'a str,
validate: bool,
strict: bool,
import_paths: &'a Vec<PathBuf>,
cache: Rc<RefCell<Cache>>,
) -> Result<build::FileBuilder<'a>, Box<dyn Error>> {
cache: Rc<RefCell<C>>,
) -> Result<build::FileBuilder<'a, C>, Box<dyn Error>> {
let mut file_path_buf = PathBuf::from(file);
if file_path_buf.is_relative() {
file_path_buf = std::env::current_dir()?.join(file_path_buf);
@ -116,11 +116,11 @@ fn build_file<'a>(
Ok(builder)
}
fn do_validate(
fn do_validate<C: Cache>(
file: &str,
strict: bool,
import_paths: &Vec<PathBuf>,
cache: Rc<RefCell<Cache>>,
cache: Rc<RefCell<C>>,
) -> bool {
println!("Validating {}", file);
match build_file(file, true, strict, import_paths, cache) {
@ -140,11 +140,11 @@ fn do_validate(
return true;
}
fn do_compile(
fn do_compile<C: Cache>(
file: &str,
strict: bool,
import_paths: &Vec<PathBuf>,
cache: Rc<RefCell<Cache>>,
cache: Rc<RefCell<C>>,
registry: &ConverterRegistry,
) -> bool {
println!("Building {}", file);
@ -175,13 +175,13 @@ fn do_compile(
}
}
fn visit_ucg_files(
fn visit_ucg_files<C: Cache>(
path: &Path,
recurse: bool,
validate: bool,
strict: bool,
import_paths: &Vec<PathBuf>,
cache: Rc<RefCell<Cache>>,
cache: Rc<RefCell<C>>,
registry: &ConverterRegistry,
) -> Result<bool, Box<dyn Error>> {
let our_path = String::from(path.to_string_lossy());
@ -252,10 +252,10 @@ fn visit_ucg_files(
Ok(result)
}
fn inspect_command(
fn inspect_command<C: Cache>(
matches: &clap::ArgMatches,
import_paths: &Vec<PathBuf>,
cache: Rc<RefCell<Cache>>,
cache: Rc<RefCell<C>>,
registry: &ConverterRegistry,
strict: bool,
) {
@ -315,10 +315,10 @@ fn inspect_command(
}
}
fn build_command(
fn build_command<C: Cache>(
matches: &clap::ArgMatches,
import_paths: &Vec<PathBuf>,
cache: Rc<RefCell<Cache>>,
cache: Rc<RefCell<C>>,
registry: &ConverterRegistry,
strict: bool,
) {
@ -414,10 +414,10 @@ fn fmt_command(matches: &clap::ArgMatches) -> std::result::Result<(), Box<dyn Er
Ok(())
}
fn test_command(
fn test_command<C: Cache>(
matches: &clap::ArgMatches,
import_paths: &Vec<PathBuf>,
cache: Rc<RefCell<Cache>>,
cache: Rc<RefCell<C>>,
registry: &ConverterRegistry,
strict: bool,
) {
@ -513,9 +513,9 @@ fn env_help() {
);
}
fn do_repl(
fn do_repl<C: Cache>(
import_paths: &Vec<PathBuf>,
cache: Rc<RefCell<Cache>>,
cache: Rc<RefCell<C>>,
) -> std::result::Result<(), Box<dyn Error>> {
let config = rustyline::Config::builder();
let mut editor = rustyline::Editor::<()>::with_config(
@ -580,7 +580,7 @@ fn do_repl(
}
}
fn repl(import_paths: &Vec<PathBuf>, cache: Rc<RefCell<Cache>>) {
fn repl<C: Cache>(import_paths: &Vec<PathBuf>, cache: Rc<RefCell<C>>) {
if let Err(e) = do_repl(import_paths, cache) {
eprintln!("{}", e);
process::exit(1);
@ -590,7 +590,7 @@ fn repl(import_paths: &Vec<PathBuf>, cache: Rc<RefCell<Cache>>) {
fn main() {
let mut app = do_flags();
let app_matches = app.clone().get_matches();
let cache: Rc<RefCell<Cache>> = Rc::new(RefCell::new(MemoryCache::new()));
let cache = Rc::new(RefCell::new(MemoryCache::new()));
let registry = ConverterRegistry::make_registry();
let mut import_paths = Vec::new();
if let Some(mut p) = dirs::home_dir() {