summaryrefslogtreecommitdiff
path: root/dhall/src/syntax/ast/import.rs
blob: 69f4021b0e42c9fe1cdcf00125706c9f5217b1d3 (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
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
use crate::syntax::trivial_result;

/// The beginning of a file path which anchors subsequent path components
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum FilePrefix {
    /// Absolute path
    Absolute,
    /// Path relative to .
    Here,
    /// Path relative to ..
    Parent,
    /// Path relative to ~
    Home,
}

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct FilePath {
    pub file_path: Vec<String>,
}

/// The location of import (i.e. local vs. remote vs. environment)
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum ImportTarget<SubExpr> {
    Local(FilePrefix, FilePath),
    Remote(URL<SubExpr>),
    Env(String),
    Missing,
}

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct URL<SubExpr> {
    pub scheme: Scheme,
    pub authority: String,
    pub path: FilePath,
    pub query: Option<String>,
    pub headers: Option<SubExpr>,
}

#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum Scheme {
    HTTP,
    HTTPS,
}

/// How to interpret the import's contents (i.e. as Dhall code or raw text)
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum ImportMode {
    Code,
    RawText,
    Location,
}

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum Hash {
    SHA256(Box<[u8]>),
}

/// Reference to an external resource
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Import<SubExpr> {
    pub mode: ImportMode,
    pub location: ImportTarget<SubExpr>,
    pub hash: Option<Hash>,
}

impl<SE> URL<SE> {
    pub fn traverse_ref<'a, Err, SE2>(
        &'a self,
        f: impl FnOnce(&'a SE) -> Result<SE2, Err>,
    ) -> Result<URL<SE2>, Err> {
        let headers = self.headers.as_ref().map(f).transpose()?;
        Ok(URL {
            scheme: self.scheme,
            authority: self.authority.clone(),
            path: self.path.clone(),
            query: self.query.clone(),
            headers,
        })
    }
    pub fn map_ref<'a, SE2>(
        &'a self,
        f: impl FnOnce(&'a SE) -> SE2,
    ) -> URL<SE2> {
        trivial_result(self.traverse_ref(|x| Ok(f(x))))
    }
}

impl<SE> ImportTarget<SE> {
    pub fn traverse_ref<'a, Err, SE2>(
        &'a self,
        f: impl FnOnce(&'a SE) -> Result<SE2, Err>,
    ) -> Result<ImportTarget<SE2>, Err> {
        use ImportTarget::*;
        Ok(match self {
            Local(prefix, path) => Local(*prefix, path.clone()),
            Remote(url) => Remote(url.traverse_ref(f)?),
            Env(env) => Env(env.clone()),
            Missing => Missing,
        })
    }
    pub fn map_ref<'a, SE2>(
        &'a self,
        f: impl FnOnce(&'a SE) -> SE2,
    ) -> ImportTarget<SE2> {
        trivial_result(self.traverse_ref(|x| Ok(f(x))))
    }
}

impl<SE> Import<SE> {
    pub fn traverse_ref<'a, Err, SE2>(
        &'a self,
        f: impl FnOnce(&'a SE) -> Result<SE2, Err>,
    ) -> Result<Import<SE2>, Err> {
        Ok(Import {
            mode: self.mode,
            location: self.location.traverse_ref(f)?,
            hash: self.hash.clone(),
        })
    }
    pub fn map_ref<'a, SE2>(
        &'a self,
        f: impl FnOnce(&'a SE) -> SE2,
    ) -> Import<SE2> {
        trivial_result(self.traverse_ref(|x| Ok(f(x))))
    }
}