]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/leaf/examples/lua_callback_result.cpp
buildsys: change download over to reef release
[ceph.git] / ceph / src / boost / libs / leaf / examples / lua_callback_result.cpp
1 // Copyright (c) 2018-2020 Emil Dotchevski and Reverge Studios, Inc.
2
3 // Distributed under the Boost Software License, Version 1.0. (See accompanying
4 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
5
6 // This is a simple program that shows how to report error objects out of a
7 // C-callback, converting them to leaf::result<T> as soon as controlreaches C++.
8
9 extern "C" {
10 #include "lua.h"
11 #include "lauxlib.h"
12 }
13 #include <boost/leaf/handle_errors.hpp>
14 #include <boost/leaf/result.hpp>
15 #include <boost/leaf/on_error.hpp>
16 #include <iostream>
17 #include <stdlib.h>
18
19 namespace leaf = boost::leaf;
20
21 enum do_work_error_code
22 {
23 ec1=1,
24 ec2
25 };
26
27 struct e_lua_pcall_error { int value; };
28 struct e_lua_error_message { std::string value; };
29
30
31 // This is a C callback with a specific signature, callable from programs written in Lua.
32 // If it succeeds, it returns an int answer, by pushing it onto the Lua stack. But "sometimes"
33 // it fails, in which case it calls luaL_error. This causes the Lua interpreter to abort and
34 // pop back into the C++ code which called it (see call_lua below).
35 int do_work( lua_State * L )
36 {
37 bool success = rand()%2; // "Sometimes" do_work fails.
38 if( success )
39 {
40 lua_pushnumber(L, 42); // Success, push the result on the Lua stack, return to Lua.
41 return 1;
42 }
43 else
44 {
45 return leaf::new_error(ec1), luaL_error(L,"do_work_error"); // luaL_error does not return (longjmp).
46 }
47 }
48
49
50 std::shared_ptr<lua_State> init_lua_state()
51 {
52 // Create a new lua_State, we'll use std::shared_ptr for automatic cleanup.
53 std::shared_ptr<lua_State> L(lua_open(), &lua_close);
54
55 // Register the do_work function (above) as a C callback, under the global
56 // Lua name "do_work". With this, calls from Lua programs to do_work
57 // will land in the do_work C function we've registered.
58 lua_register( &*L, "do_work", &do_work );
59
60 // Pass some Lua code as a C string literal to Lua. This creates a global Lua
61 // function called "call_do_work", which we will later ask Lua to execute.
62 luaL_dostring( &*L, "\
63 \n function call_do_work()\
64 \n return do_work()\
65 \n end" );
66
67 return L;
68 }
69
70
71 // Here we will ask Lua to execute the function call_do_work, which is written
72 // in Lua, and returns the value from do_work, which is written in C++ and
73 // registered with the Lua interpreter as a C callback.
74
75 // If do_work succeeds, we return the resulting int answer.
76 // If it fails, we'll communicate that failure to our caller.
77 leaf::result<int> call_lua( lua_State * L )
78 {
79 leaf::error_monitor cur_err;
80
81 // Ask the Lua interpreter to call the global Lua function call_do_work.
82 lua_getfield( L, LUA_GLOBALSINDEX, "call_do_work" );
83 if( int err = lua_pcall(L, 0, 1, 0) ) // Ask Lua to call the global function call_do_work.
84 {
85 auto load = leaf::on_error(e_lua_error_message{lua_tostring(L, 1)});
86 lua_pop(L,1);
87
88 // We got a Lua error which may be the error we're reporting from do_work, or some other error.
89 // If it is another error, cur_err.assigned_error_id() will return a new leaf::error_id,
90 // otherwise we'll be working with the original value returned by leaf::new_error in do_work.
91 return cur_err.assigned_error_id().load(e_lua_pcall_error{err});
92 }
93 else
94 {
95 // Success! Just return the int answer.
96 int answer=lua_tonumber(L, -1);
97 lua_pop(L,1);
98 return answer;
99 }
100 }
101
102 int main()
103 {
104 std::shared_ptr<lua_State> L=init_lua_state();
105
106 for( int i=0; i!=10; ++i )
107 {
108 leaf::try_handle_all(
109
110 [&]() -> leaf::result<void>
111 {
112 BOOST_LEAF_AUTO(answer, call_lua(&*L));
113 std::cout << "do_work succeeded, answer=" << answer << '\n';
114 return { };
115 },
116
117 []( do_work_error_code e )
118 {
119 std::cout << "Got do_work_error_code = " << e << "!\n";
120 },
121
122 []( e_lua_pcall_error const & err, e_lua_error_message const & msg )
123 {
124 std::cout << "Got e_lua_pcall_error, Lua error code = " << err.value << ", " << msg.value << "\n";
125 },
126
127 []( leaf::error_info const & unmatched )
128 {
129 std::cerr <<
130 "Unknown failure detected" << std::endl <<
131 "Cryptic diagnostic information follows" << std::endl <<
132 unmatched;
133 } );
134 }
135
136 return 0;
137 }
138
139 #ifdef BOOST_LEAF_NO_EXCEPTIONS
140
141 namespace boost
142 {
143 BOOST_LEAF_NORETURN void throw_exception( std::exception const & e )
144 {
145 std::cerr << "Terminating due to a C++ exception under BOOST_LEAF_NO_EXCEPTIONS: " << e.what();
146 std::terminate();
147 }
148
149 struct source_location;
150 BOOST_LEAF_NORETURN void throw_exception( std::exception const & e, boost::source_location const & )
151 {
152 throw_exception(e);
153 }
154 }
155
156 #endif