aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/libs/jinja2cpp/src/template_env.cpp
blob: 239a4f02e1105b4f6ea7c875b86d2a516d3efe78 (plain) (blame)
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
#include <jinja2cpp/template.h>
#include <jinja2cpp/template_env.h>

namespace jinja2
{
template<typename CharT>
struct TemplateFunctions;

template<>
struct TemplateFunctions<char>
{
    using ResultType = nonstd::expected<Template, ErrorInfo>;
    static Template CreateTemplate(TemplateEnv* env) { return Template(env); }
    static auto LoadFile(const std::string& fileName, const IFilesystemHandler* fs) { return fs->OpenStream(fileName); }
};

template<>
struct TemplateFunctions<wchar_t>
{
    using ResultType = nonstd::expected<TemplateW, ErrorInfoW>;
    static TemplateW CreateTemplate(TemplateEnv* env) { return TemplateW(env); }
    static auto LoadFile(const std::string& fileName, const IFilesystemHandler* fs) { return fs->OpenWStream(fileName); }
};

template<typename CharT, typename T, typename Cache>
auto TemplateEnv::LoadTemplateImpl(TemplateEnv* env, std::string fileName, const T& filesystemHandlers, Cache& cache)
{
    using Functions = TemplateFunctions<CharT>;
    using ResultType = typename Functions::ResultType;
    using ErrorType = typename ResultType::error_type;
    auto tpl = Functions::CreateTemplate(env);

    {
        std::shared_lock<std::shared_timed_mutex> l(m_guard);
        auto p = cache.find(fileName);
        if (p != cache.end())
        {
            if (m_settings.autoReload)
            {
                auto lastModified = p->second.handler->GetLastModificationDate(fileName);
                if (!lastModified || (p->second.lastModification && lastModified.value() <= p->second.lastModification.value()))
                    return ResultType(p->second.tpl);
            }
            else
                return ResultType(p->second.tpl);
        }
    }

    for (auto& fh : filesystemHandlers)
    {
        if (!fh.prefix.empty() && fileName.find(fh.prefix) != 0)
            continue;

        auto stream = Functions::LoadFile(fileName, fh.handler.get());
        if (stream)
        {
            auto res = tpl.Load(*stream, fileName);
            if (!res)
                return ResultType(res.get_unexpected());

            if (m_settings.cacheSize != 0)
            {
                auto lastModified = fh.handler->GetLastModificationDate(fileName);
                std::unique_lock<std::shared_timed_mutex> l(m_guard);
                auto& cacheEntry = cache[fileName];
                cacheEntry.tpl = tpl;
                cacheEntry.handler = fh.handler;
                cacheEntry.lastModification = lastModified;
            }

            return ResultType(tpl);
        }
    }

    typename ErrorType::Data errorData;
    errorData.code = ErrorCode::FileNotFound;
    errorData.srcLoc.col = 1;
    errorData.srcLoc.line = 1;
    errorData.srcLoc.fileName = "";
    errorData.extraParams.push_back(Value(fileName));

    return ResultType(nonstd::make_unexpected(ErrorType(errorData)));
}

nonstd::expected<Template, ErrorInfo> TemplateEnv::LoadTemplate(std::string fileName)
{
    return LoadTemplateImpl<char>(this, std::move(fileName), m_filesystemHandlers, m_templateCache);
}

nonstd::expected<TemplateW, ErrorInfoW> TemplateEnv::LoadTemplateW(std::string fileName)
{
    return LoadTemplateImpl<wchar_t>(this, std::move(fileName), m_filesystemHandlers, m_templateWCache);
}

} // namespace jinja2