summaryrefslogtreecommitdiffstats
path: root/src/wesl.rs
blob: aaaf97d930dca0ad96e361d49151927a465d1409 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
use std::borrow::Cow;
use std::iter;
use std::path::PathBuf;

use wesl::{
    syntax::PathOrigin, EscapeMangler, FileResolver, Mangler, ModulePath, ResolveError, Resolver,
    VirtualResolver, Wesl,
};

pub struct ShaderSources {
    virtual_resolver: VirtualResolver<'static>,
    file_resolver: Option<FileResolver>,
    mangler: EscapeMangler,
}

impl Default for ShaderSources {
    fn default() -> Self {
        Self::new(Some("wesl-lib".into()))
    }
}

impl ShaderSources {
    pub fn new(lib_dir: Option<PathBuf>) -> Self {
        Self {
            virtual_resolver: VirtualResolver::new(),
            file_resolver: lib_dir.map(FileResolver::new),
            mangler: Default::default(),
        }
    }

    pub fn set_module(&mut self, module: ModulePath, source: impl Into<String>) {
        self.virtual_resolver
            .add_module(module, Cow::Owned(source.into()));
    }

    pub fn compile(&mut self, root_module: &ModulePath) -> Result<String, wesl::Error> {
        Wesl::new_barebones()
            .set_custom_resolver(&*self)
            .set_custom_mangler(self.mangler.clone())
            .set_options(wesl::CompileOptions {
                mangle_root: true,
                ..Default::default()
            })
            .compile(root_module)
            .map(|compiled| compiled.to_string())
    }

    pub fn mangler(&self) -> &impl Mangler {
        &self.mangler
    }
}

impl Resolver for ShaderSources {
    fn resolve_source<'a>(&'a self, path: &ModulePath) -> Result<Cow<'a, str>, ResolveError> {
        match path.origin {
            PathOrigin::Absolute => self.virtual_resolver.resolve_source(path),
            PathOrigin::Package(ref pname) => {
                if let Some(ref files) = self.file_resolver {
                    let fpath = ModulePath {
                        origin: PathOrigin::Absolute,
                        components: iter::once(pname)
                            .chain(path.components.iter())
                            .cloned()
                            .collect(),
                    };
                    files.resolve_source(&fpath)
                } else {
                    Err(ResolveError::ModuleNotFound(
                        path.clone(),
                        "no library director found".into(),
                    ))
                }
            }
            _ => Err(ResolveError::ModuleNotFound(
                path.clone(),
                "can't resolve relative module".into(),
            )),
        }
    }
}