With the styles API, a lot more API surface area will be publicly exposed:
Style
Source and future subclasses for specific source types
StyleLayer and subclasses for specific layer types
- Paint and layout properties for all layer types
So far, we've been using the following technique for separating public APIs from private implementation:
- Public headers live in
include, private headers live in src
- Public headers use forward declarations and pointers to avoid needing to include private headers
For the styles API, I don't think this is going to be enough. For example, I don't think we want to simply make style_layer.hpp a public include file -- it would cascade into making other headers public as well, and expose implementation details we want to be free to change. The current StyleLayer and subclasses depend on rapidjson headers (not easily forward declared) and have methods that are conceptually public to other mbgl internal classes, but private to API consumers (e.g. cascade, recalculate, createBucket).
Therefore we need to use more heavy-duty techniques to separate the public API from private implementation. I propose we adopt a particular implementation of the opaque pointer pattern, and follow this convention throughout portions of the codebase exposed to the public API:
- Public header files expose objects in the
mbgl namespace. (Already doing this.)
- These objects hold a pointer to a corresponding instance of a class with the same name, but in the
mbgl::impl namespace.
- All implementation code moves to the
mbgl::impl namespace and src/mbgl/impl directory tree.
Example:
include/mbgl/map.hpp
namespace mbgl {
namespace impl { class Map; }
class Map {
public:
void doSomething();
private:
std::unique_ptr<impl::Map> impl;
};
}
src/mbgl/map.cpp
namespace mbgl {
void Map::doSomething() {
impl->a.doSomething();
impl->b.doSomethingElse();
}
}
src/mbgl/impl/map.hpp
#include <mbgl/map.hpp>
#include <mbgl/impl/foo.hpp>
#include <mbgl/impl/bar.hpp>
namespace mbgl {
namespace impl {
class Map {
public:
Foo a;
Bar b;
};
}
}
In this example I've shown implementing mbgl::Map::doSomething in src/mbgl/map.cpp. Another option is to forward to mbgl::impl::Map::doSomething and put the real implementation in src/mbgl/impl/map.cpp. But that's another level of indirection and I don't know if there's any benefit.
Thoughts?
With the styles API, a lot more API surface area will be publicly exposed:
StyleSourceand future subclasses for specific source typesStyleLayerand subclasses for specific layer typesSo far, we've been using the following technique for separating public APIs from private implementation:
include, private headers live insrcFor the styles API, I don't think this is going to be enough. For example, I don't think we want to simply make
style_layer.hppa public include file -- it would cascade into making other headers public as well, and expose implementation details we want to be free to change. The currentStyleLayerand subclasses depend on rapidjson headers (not easily forward declared) and have methods that are conceptually public to other mbgl internal classes, but private to API consumers (e.g.cascade,recalculate,createBucket).Therefore we need to use more heavy-duty techniques to separate the public API from private implementation. I propose we adopt a particular implementation of the opaque pointer pattern, and follow this convention throughout portions of the codebase exposed to the public API:
mbglnamespace. (Already doing this.)mbgl::implnamespace.mbgl::implnamespace andsrc/mbgl/impldirectory tree.Example:
include/mbgl/map.hpp
src/mbgl/map.cpp
src/mbgl/impl/map.hpp
In this example I've shown implementing
mbgl::Map::doSomethinginsrc/mbgl/map.cpp. Another option is to forward tombgl::impl::Map::doSomethingand put the real implementation insrc/mbgl/impl/map.cpp. But that's another level of indirection and I don't know if there's any benefit.Thoughts?