Skip to content

Commit d5ddf0f

Browse files
committed
fable: Implement Path schema for std::filesystem::path and boost::filesystem::path
BREAKING CHANGE: If you want to use boost::filesystem::path, you now need to include `fable/schema/boost_path.hpp`.
1 parent e2776ca commit d5ddf0f

File tree

11 files changed

+586
-172
lines changed

11 files changed

+586
-172
lines changed

engine/src/stack.hpp

+1
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
#include <boost/filesystem/path.hpp> // for path
3434
#include <boost/optional.hpp> // for optional<>
3535
#include <fable/schema/boost_optional.hpp> // for Optional<>
36+
#include <fable/schema/boost_path.hpp> // for Path
3637
#include <fable/schema/custom.hpp> // for CustomDeserializer
3738
#include <fable/schema/factory.hpp> // for Factory
3839

fable/CMakeLists.txt

+6-4
Original file line numberDiff line numberDiff line change
@@ -19,17 +19,18 @@ add_library(fable
1919
# find src -type f -name "*.cpp" \! -name "*_test.cpp"
2020
src/fable/conf.cpp
2121
src/fable/confable.cpp
22+
src/fable/environment.cpp
2223
src/fable/json.cpp
2324
src/fable/schema.cpp
2425
src/fable/schema/boolean.cpp
2526
src/fable/schema/number.cpp
26-
src/fable/schema/struct.cpp
27+
src/fable/schema/path.cpp
2728
src/fable/schema/string.cpp
29+
src/fable/schema/struct.cpp
2830
src/fable/schema/variant.cpp
29-
src/fable/schema/path.cpp
30-
src/fable/environment.cpp
3131
src/fable/utility.cpp
3232
src/fable/utility/chrono.cpp
33+
src/fable/utility/path.cpp
3334
src/fable/utility/string.cpp
3435

3536
# For IDE integration
@@ -76,13 +77,14 @@ if(BUILD_TESTING)
7677
src/fable/schema/const_test.cpp
7778
src/fable/schema/custom_test.cpp
7879
src/fable/schema/enum_test.cpp
79-
src/fable/schema/factory_test.cpp
8080
src/fable/schema/factory_advanced_test.cpp
81+
src/fable/schema/factory_test.cpp
8182
src/fable/schema/ignore_test.cpp
8283
src/fable/schema/map_nested_test.cpp
8384
src/fable/schema/map_test.cpp
8485
src/fable/schema/number_test.cpp
8586
src/fable/schema/optional_test.cpp
87+
src/fable/schema/path_test.cpp
8688
src/fable/schema/string_test.cpp
8789
src/fable/schema/struct_test.cpp
8890
src/fable/schema_test.cpp
+77
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
/*
2+
* Copyright 2023 Robert Bosch GmbH
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*
16+
* SPDX-License-Identifier: Apache-2.0
17+
*/
18+
/**
19+
* \file fable/schema/boost_path.hpp
20+
* \see fable/schema/path.cpp
21+
*/
22+
23+
#pragma once
24+
25+
#include <fable/schema/path.hpp>
26+
#include <fable/schema/path_impl.hpp>
27+
#include <fable/utility/boost_path.hpp>
28+
29+
#include <boost/filesystem/path.hpp>
30+
#include <boost/process/search_path.hpp>
31+
32+
namespace fable {
33+
namespace schema {
34+
35+
template <>
36+
struct is_path<boost::filesystem::path> : std::true_type {};
37+
38+
namespace detail {
39+
40+
template <>
41+
inline bool exists(const boost::filesystem::path& path) {
42+
return boost::filesystem::exists(path);
43+
}
44+
45+
template <>
46+
inline bool is_regular_file(const boost::filesystem::path& path) {
47+
return boost::filesystem::is_regular_file(path);
48+
}
49+
50+
template <>
51+
inline bool is_directory(const boost::filesystem::path& path) {
52+
return boost::filesystem::is_directory(path);
53+
}
54+
55+
template <>
56+
inline bool is_other(const boost::filesystem::path& path) {
57+
return boost::filesystem::is_other(path);
58+
}
59+
60+
template <>
61+
inline boost::filesystem::path canonical(const boost::filesystem::path& path) {
62+
return boost::filesystem::canonical(path);
63+
}
64+
65+
template <>
66+
inline std::optional<boost::filesystem::path> search_path(const boost::filesystem::path& executable) {
67+
boost::filesystem::path path = boost::process::search_path(executable);
68+
if (path.empty()) {
69+
return std::nullopt;
70+
}
71+
return path;
72+
}
73+
74+
} // namespace detail
75+
76+
} // namespace schema
77+
} // namespace fable

fable/include/fable/schema/path.hpp

+47-37
Original file line numberDiff line numberDiff line change
@@ -23,20 +23,46 @@
2323

2424
#pragma once
2525

26-
#include <limits> // for numeric_limits<>
27-
#include <string> // for string
28-
#include <utility> // for move
29-
30-
#include <boost/filesystem/path.hpp> // for path
26+
#include <filesystem> // for path
27+
#include <limits> // for numeric_limits<>
28+
#include <string> // for string
29+
#include <utility> // for move
3130

31+
#include <fable/fable_fwd.hpp> // for Environment
3232
#include <fable/schema/interface.hpp> // for Base<>
33+
#include <fable/utility/path.hpp> // for adl_serializer<>
3334

3435
namespace fable {
36+
namespace schema {
3537

36-
// Forward declarations:
37-
class Environment; // from <fable/environment.hpp>
38+
/**
39+
* Helper type trait class to use with std::enable_if and friends.
40+
*
41+
* The value `is_path<T>::value` is true if T is one of:
42+
* - std::filesystem::path
43+
* - boost::filesystem::path, if boost_path.hpp is included
44+
*
45+
* \see fable/schema/boost_path.hpp
46+
*/
47+
template <typename T>
48+
struct is_path : std::false_type {};
3849

39-
namespace schema {
50+
template <>
51+
struct is_path<std::filesystem::path> : std::true_type {};
52+
53+
/**
54+
* State represents valid states a path can be in relative to the filesystem.
55+
*/
56+
enum class PathState {
57+
Any, /// any valid path
58+
Absent, /// path does not exist
59+
Exists, /// path exists
60+
Executable, /// path exists in search path or locally and has executable permission
61+
FileExists, /// path exists and is a file
62+
DirExists, /// path exists and is a directory
63+
NotFile, /// path does not exist or is a directory
64+
NotDir, /// path does not exist or is a file
65+
};
4066

4167
/**
4268
* Path de-/serializes a string that represents a filesystem path.
@@ -52,26 +78,20 @@ namespace schema {
5278
*
5379
* The Path schema type allows the user to specify these properties and will
5480
* validate these during deserialization.
81+
*
82+
* Path is a template class that supports both:
83+
* - std::filesystem::path
84+
* - boost::filesystem::path, if boost_path.hpp is included
5585
*/
56-
class Path : public Base<Path> {
86+
template <typename T>
87+
class Path : public Base<Path<T>> {
88+
static_assert(is_path<T>::value);
89+
5790
public: // Types and Constructors
58-
using Type = boost::filesystem::path;
91+
using Type = T;
92+
using State = PathState;
5993

60-
/**
61-
* State represents valid states a path can be in relative to the filesystem.
62-
*/
63-
enum class State {
64-
Any, /// any valid path
65-
Absent, /// path does not exist
66-
Exists, /// path exists
67-
Executable, /// path exists in search path or locally and has executable permission
68-
FileExists, /// path exists and is a file
69-
DirExists, /// path exists and is a directory
70-
NotFile, /// path does not exist or is a directory
71-
NotDir, /// path does not exist or is a file
72-
};
73-
74-
Path(Type* ptr, std::string desc) : Base(JsonType::string, std::move(desc)), ptr_(ptr) {}
94+
Path(Type* ptr, std::string desc) : Base<Path<T>>(JsonType::string, std::move(desc)), ptr_(ptr) {}
7595

7696
public: // Special
7797
/**
@@ -213,20 +233,10 @@ class Path : public Base<Path> {
213233
Type* ptr_{nullptr};
214234
};
215235

216-
template <typename S>
217-
inline Path make_schema(boost::filesystem::path* ptr, S&& desc) {
236+
template <typename T, typename S, std::enable_if_t<is_path<T>::value, bool> = true>
237+
inline Path<T> make_schema(T* ptr, S&& desc) {
218238
return Path(ptr, std::forward<S>(desc));
219239
}
220240

221241
} // namespace schema
222242
} // namespace fable
223-
224-
namespace nlohmann {
225-
226-
template <>
227-
struct adl_serializer<boost::filesystem::path> {
228-
static void to_json(json& j, const boost::filesystem::path& p) { j = p.native(); }
229-
static void from_json(const json& j, boost::filesystem::path& p) { p = j.get<std::string>(); }
230-
};
231-
232-
} // namespace nlohmann

0 commit comments

Comments
 (0)