1 /* Documentation snippet
2 (C) 2017-2019 Niall Douglas <http://www.nedproductions.biz/> (8 commits)
3 File Created: Mar 2017
4 
5 
6 Boost Software License - Version 1.0 - August 17th, 2003
7 
8 Permission is hereby granted, free of charge, to any person or organization
9 obtaining a copy of the software and accompanying documentation covered by
10 this license (the "Software") to use, reproduce, display, distribute,
11 execute, and transmit the Software, and to prepare derivative works of the
12 Software, and to permit third-parties to whom the Software is furnished to
13 do so, all subject to the following:
14 
15 The copyright notices in the Software and this entire statement, including
16 the above license grant, this restriction and the following disclaimer,
17 must be included in all copies of the Software, in whole or in part, and
18 all derivative works of the Software, unless such copies or derivative
19 works are solely in the form of machine-executable object code generated by
20 a source language processor.
21 
22 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
25 SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
26 FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
27 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
28 DEALINGS IN THE SOFTWARE.
29 */
30 
31 #include "../../../include/boost/outcome.hpp"
32 #include <experimental/filesystem>
33 
34 namespace outcome = BOOST_OUTCOME_V2_NAMESPACE;
35 
36 namespace filesystem
37 {
38   using std::experimental::filesystem::path;
copy_file(const path & from,const path & to)39   bool copy_file(const path &from, const path &to) { return false; }
copy_file(const path & from,const path & to,std::error_code & ec)40   bool copy_file(const path &from, const path &to, std::error_code &ec) { return false; }
41 }
42 namespace filesystem2
43 {
44   using std::experimental::filesystem::path;
45   using std::experimental::filesystem::filesystem_error;
46 }
47 
48 //! [filesystem_api_problem]
49 namespace filesystem
50 {
51   /*! Copies the file at path `from` to path `to`.
52   \returns True if file was successfully copied.
53   \throws On failure throws `filesystem_error(ec.message(), from, to, ec)` with
54   `ec` being the error code reported by the operating system.
55   */
56   bool copy_file(const path &from, const path &to);
57 
58   /*! Copies the file at path `from` to path `to`.
59   \returns True if file was successfully copied. If false, `ec` is written with
60   the error code reported by the operating system.
61   \throws May throw an exception if there is some "catastrophic" failure
62   e.g. failure to allocate memory.
63   */
64   bool copy_file(const path &from, const path &to, std::error_code &ec);
65 }
66 //! [filesystem_api_problem]
67 
68 //! [filesystem_api_fixed]
69 namespace filesystem2
70 {
71   // Error code + paths related to a failure. Also causes ADL discovery to check this namespace.
72   struct failure_info
73   {
74     std::error_code ec;
75     path path1, path2;
76   };
77 
78   // Tell Outcome that failure_info is to be treated as a std::error_code
make_error_code(const failure_info & fi)79   inline const std::error_code &make_error_code(const failure_info &fi) { return fi.ec; }
80 
81   // Localise an outcome implementation specific to this namespace. Normally would just
82   // be `result`, but for clarity we'll use `fs_result`.
83   template <class T> using fs_result = outcome::result<T, failure_info>;
84 
85   /*! Copies the file at path `from` to path `to`.
86   \returns Successful if file was successfully copied, otherwise the error code reported
87   by the operating system plus a payload of the paths involved.
88   \throws Never throws.
89   */
90   fs_result<void> copy_file(const path &from, const path &to) noexcept;
91 }
92 //! [filesystem_api_fixed]
93 
94 namespace filesystem2
95 {
copy_file(const path & from,const path & to)96   fs_result<void> copy_file(const path &from, const path &to) noexcept { return failure_info{make_error_code(std::errc::no_such_file_or_directory), from, to}; }
97 }
98 
99 //! [filesystem_api_custom_throw]
100 namespace filesystem2
101 {
102   // If we would like Outcome to do something other than the default action (see next
103   // section), we can declare this ADL discovered free function to customise what
104   // to do instead.
105   //
106   // Note that rvalue semantics are propagated internally by Outcome, so if the user
107   // called .value() on a rvalued result, failure_info will be moved rather than
108   // copied from the result. That means we can overload once with value semantics,
109   // and not need to overload for lvalue and rvalue situations unless we really feel
110   // we need to for some reason.
outcome_throw_as_system_error_with_payload(failure_info fi)111   inline void outcome_throw_as_system_error_with_payload(failure_info fi)
112   {
113     // If the error code is not filesystem related e.g. ENOMEM, throw that as a
114     // standard STL exception.
115     outcome::try_throw_std_exception_from_error(fi.ec);
116     // Throw the exact same filesystem_error exception which the throwing copy_file()
117     // edition does.
118     throw filesystem_error(fi.ec.message(), std::move(fi.path1),  //
119                            std::move(fi.path2), fi.ec);
120   }
121 }
122 //! [filesystem_api_custom_throw]
123 
main()124 int main()
125 {
126   //! [filesystem_api_custom_throw_demo]
127   // Non-throwing use case
128   auto o = filesystem2::copy_file("dontexist", "alsodontexist");
129   if(!o)
130   {
131     std::cerr << "Copy file failed with error " << o.error().ec.message()                   //
132               << " (path1 = " << o.error().path1 << ", path2 = " << o.error().path2 << ")"  //
133               << std::endl;
134   }
135 
136   // Throwing use case
137   try
138   {
139     // Try to observe the successful value, thus triggering default actions which invokes
140     // our outcome_throw_as_system_error_with_payload() above which then throws filesystem_error
141     // exactly like the Filesystem TS does for its throwing overload.
142     filesystem2::copy_file("dontexist", "alsodontexist").value();
143   }
144   catch(const filesystem2::filesystem_error &e)
145   {
146     std::cerr << "Copy file failed with exception " << e.what()                 //
147               << " (path1 = " << e.path1() << ", path2 = " << e.path2() << ")"  //
148               << std::endl;
149   }
150   catch(const std::exception &e)
151   {
152     std::cerr << "Copy file failed with exception " << e.what()  //
153               << std::endl;
154   }
155   //! [filesystem_api_custom_throw_demo]
156   return 0;
157 }