Turi Create  4.0
toolkit_function_macros.hpp
1 /* Copyright © 2017 Apple Inc. All rights reserved.
2  *
3  * Use of this source code is governed by a BSD-3-clause license that can
4  * be found in the LICENSE.txt file or at https://opensource.org/licenses/BSD-3-Clause
5  */
6 #ifndef TURI_UNITY_TOOLKIT_FUNCTION_MACROS_HPP
7 #define TURI_UNITY_TOOLKIT_FUNCTION_MACROS_HPP
8 #include <model_server/lib/toolkit_util.hpp>
9 #include <model_server/lib/toolkit_function_specification.hpp>
10 #include <model_server/lib/toolkit_function_wrapper_impl.hpp>
11 #include <model_server/lib/toolkit_class_wrapper_impl.hpp>
12 
13 
14 /**************************************************************************/
15 /* */
16 /* Function Registration */
17 /* */
18 /**************************************************************************/
19 /**
20  * \defgroup group_gl_function_ffi Function Extension Interface
21  * \ingroup group_gl_ffi
22  *
23  * The Function Extension Interface provides a collection of macros that automate
24  * the process of exporting a function to Python. The macros are located in
25  * sdk/toolkit_function_macros.hpp .
26  *
27  * For detailed usage descriptions, see page_turicreate_extension_interface .
28  *
29  * Example:
30  * \code
31  * #include <string>
32  * #include <model_server/lib/toolkit_function_macros.hpp>
33  * using namespace turi;
34  *
35  * std::string demo_to_string(int in) {
36  * return std::to_string(in);
37  * }
38  *
39  * BEGIN_FUNCTION_REGISTRATION
40  * REGISTER_FUNCTION(demo_to_string, "in");
41  * END_FUNCTION_REGISTRATION
42  * \endcode
43  * \{
44  */
45 
46 /**
47  * Begins a toolkit registration block.
48  *
49  * \see END_FUNCTION_REGISTRATION
50  * \see REGISTER_FUNCTION
51  *
52  * The basic usage is:
53  * \code
54  * BEGIN_FUNCTION_REGISTRATION
55  * REGISTER_FUNCTION(my_function, inargname1, inargname2 ...)
56  * REGISTER_FUNCTION(my_function2, inargname1, ...)
57  * END_FUNCTION_REGISTRATION
58  * \endcode
59  *
60  */
61 #define BEGIN_FUNCTION_REGISTRATION \
62  __attribute__((visibility("default"))) \
63  std::vector<::turi::toolkit_function_specification> \
64  get_toolkit_function_registration() { \
65  std::vector<::turi::toolkit_function_specification> specs;
66 
67 /**
68  * Registers a function to make it callable from Python.
69  * \see BEGIN_FUNCTION_REGISTRATION
70  * \see END_FUNCTION_REGISTRATION
71  *
72  * Registers a function with no arguments.
73  * \code
74  * REGISTER_FUNCTION(function)
75  * \endcode
76  *
77  * Registers a function with 3 input arguments. The first input argument shall
78  * be named "a", the second named "b" and the 3rd named "c"
79  * \code
80  * REGISTER_FUNCTION(function, "a", "b", "c")
81  * \endcode
82  *
83  * Example:
84  *
85  * \code
86  * std::string demo_to_string(flexible_type in) {
87  * return std::string(in);
88  * }
89  *
90  * BEGIN_FUNCTION_REGISTRATION
91  * REGISTER_FUNCTION(demo_to_string, "in");
92  * END_FUNCTION_REGISTRATION
93  * \endcode
94  *
95  * Namespaces are permitted. For instance:
96  * \code
97  * namespace example {
98  * std::string demo_to_string(flexible_type in) {
99  * return std::string(in);
100  * }
101  * }
102  *
103  * BEGIN_FUNCTION_REGISTRATION
104  * REGISTER_FUNCTION(example::demo_to_string, "in");
105  * END_FUNCTION_REGISTRATION
106  * \endcode
107  *
108  * Both will be published as "demo_to_string"; the namespacing is ignored.
109  *
110  * The return value of the function will be returned to Python. The function
111  * can return void. If the function fails, it should throw an exception which
112  * will be forward back to Python as RuntimeError.
113  */
114 #define REGISTER_FUNCTION(function, ...) \
115  specs.push_back(toolkit_function_wrapper_impl::make_spec_indirect(function, #function, \
116  ##__VA_ARGS__));
117 
118 /**
119  * Register a function, assigning it a different name than the name of the function.
120  *
121  * \code
122  * std::string demo_to_string(flexible_type in) {
123  * return std::string(in);
124  * }
125  *
126  * BEGIN_FUNCTION_REGISTRATION
127  * REGISTER_NAMED_FUNCTION("module._demo_to_string", demo_to_string, "in");
128  * END_FUNCTION_REGISTRATION
129  * \endcode
130  */
131 #define REGISTER_NAMED_FUNCTION(name, function, ...) \
132  specs.push_back(toolkit_function_wrapper_impl::make_spec_indirect(function, name, \
133  ##__VA_ARGS__));
134 /**
135  * Sets a docstring on the function.
136  * If not provided, a default docstring describing the input arguments will be
137  * used. Must be called only *after* the function is registered. i.e.
138  * the matching REGISTER_FUNCTION must appear
139  * before, and it must be called with exactly the same function.
140  *
141  * \code
142  * BEGIN_FUNCTION_REGISTRATION
143  * REGISTER_FUNCTION(demo_add_one, "in");
144  * REGISTER_DOCSTRING(demo_add_one, "Adds one to an integer/float")
145  * REGISTER_DOCSTRING(demo_to_string, "Converts an arbitrary value to a string")
146  * END_FUNCTION_REGISTRATION
147  * \endcode
148  */
149 #define REGISTER_DOCSTRING(function, docstring) \
150  for (auto& i: specs) { \
151  if (i.description.count("_raw_fn_pointer_") && \
152  i.description.at("_raw_fn_pointer_") == reinterpret_cast<size_t>(function)) { \
153  i.description["documentation"] = docstring; \
154  } \
155  }
156 
157 
158 
159 /**
160  * Ends a toolkit registration block.
161  *
162  * \see BEGIN_FUNCTION_REGISTRATION.
163  * \see REGISTER_FUNCTION_FUNCTION
164  *
165  * The basic usage is:
166  * \code
167  * BEGIN_FUNCTION_REGISTRATION
168  * REGISTER_FUNCTION(my_function, inargname1, inargname2 ...)
169  * REGISTER_FUNCTION(my_function2, inargname1, ...)
170  * END_FUNCTION_REGISTRATION
171  * \endcode
172  */
173 #define END_FUNCTION_REGISTRATION \
174  return specs; \
175  }
176 
177 /// \}
178 
179 #endif // TURI_UNITY_TOOLKIT_MAGIC_MACROS_HPP