blob: 0bbff84ff32047082da085af7a3da1dfd96f09c6 (
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
|
#include <mbgl/test/stub_file_source.hpp>
namespace mbgl {
using namespace std::chrono_literals;
class StubFileRequest : public AsyncRequest {
public:
StubFileRequest(StubFileSource& fileSource_)
: fileSource(fileSource_) {
}
~StubFileRequest() override {
fileSource.remove(this);
}
StubFileSource& fileSource;
};
StubFileSource::StubFileSource(ResponseType type_)
: type(type_) {
if (type == ResponseType::Synchronous) {
return;
}
timer.start(1ms, 1ms, [this] {
// Explicit copy to avoid iterator invalidation if ~StubFileRequest gets called within the loop.
auto pending_ = pending;
for (auto& pair : pending_) {
optional<Response> res = std::get<1>(pair.second)(std::get<0>(pair.second));
if (res) {
// This must be before calling the callback, because it's possible that the callback
// could:
//
// 1. Deallocate the AsyncRequest itself, thus removing it from pending
// 2. Allocate a new AsyncRequest at the same memory location
//
// If remove(pair.first) was called after both those things happened, it would
// remove the newly allocated request rather than the intended request.
if (!res->error) {
remove(pair.first);
}
std::get<2>(pair.second)(*res);
}
}
});
}
StubFileSource::~StubFileSource() = default;
std::unique_ptr<AsyncRequest> StubFileSource::request(const Resource& resource, Callback callback) {
auto req = std::make_unique<StubFileRequest>(*this);
if (type == ResponseType::Synchronous) {
optional<Response> res = response(resource);
if (res) {
callback(*res);
}
} else {
pending.emplace(req.get(), std::make_tuple(resource, response, callback));
}
return std::move(req);
}
void StubFileSource::remove(AsyncRequest* req) {
auto it = pending.find(req);
if (it != pending.end()) {
pending.erase(it);
}
}
optional<Response> StubFileSource::defaultResponse(const Resource& resource) {
switch (resource.kind) {
case Resource::Kind::Style:
if (!styleResponse) throw std::runtime_error("unexpected style request");
return styleResponse(resource);
case Resource::Kind::Source:
if (!sourceResponse) throw std::runtime_error("unexpected source request");
return sourceResponse(resource);
case Resource::Kind::Tile:
if (!tileResponse) throw std::runtime_error("unexpected tile request");
return tileResponse(resource);
case Resource::Kind::Glyphs:
if (!glyphsResponse) throw std::runtime_error("unexpected glyphs request");
return glyphsResponse(resource);
case Resource::Kind::SpriteJSON:
if (!spriteJSONResponse) throw std::runtime_error("unexpected sprite JSON request");
return spriteJSONResponse(resource);
case Resource::Kind::SpriteImage:
if (!spriteImageResponse) throw std::runtime_error("unexpected sprite image request");
return spriteImageResponse(resource);
case Resource::Kind::Image:
if (!imageResponse) throw std::runtime_error("unexpected image request");
return imageResponse(resource);
case Resource::Kind::Unknown:
throw std::runtime_error("unknown resource type");
}
// The above switch is exhaustive, but placate GCC nonetheless:
return Response();
}
} // namespace mbgl
|