aboutsummaryrefslogtreecommitdiffstats
path: root/common/pybindings.h
blob: a99ad51b1e8428ce003d75d74820abae5131b634 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
/*
 *  nextpnr -- Next Generation Place and Route
 *
 *  Copyright (C) 2018  Clifford Wolf <clifford@clifford.at>
 *  Copyright (C) 2018  David Shah <dave@ds0.me>
 *
 *  Permission to use, copy, modify, and/or distribute this software for any
 *  purpose with or without fee is hereby granted, provided that the above
 *  copyright notice and this permission notice appear in all copies.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 *
 */

#ifndef COMMON_PYBINDINGS_H
#define COMMON_PYBINDINGS_H

#include "pycontainers.h"

#include <utility>
#include <stdexcept>
#include <boost/python.hpp>
#include <boost/python/suite/indexing/vector_indexing_suite.hpp>
#include <boost/python/suite/indexing/map_indexing_suite.hpp>
#include <boost/python/suite/indexing/map_indexing_suite.hpp>
#include <Python.h>
using namespace boost::python;

/*
A wrapper to enable custom type/ID to/from string conversions
 */
template<typename T>
struct string_wrapper {
	template<typename F>
	struct from_pystring_converter {
		from_pystring_converter() {
			converter::registry::push_back(
					&convertible,
					&construct,
					boost::python::type_id<T>());
		};

		static void *convertible(PyObject *object) {
			return PyUnicode_Check(object) ? object : 0;
		}

		static void construct(
				PyObject *object,
				converter::rvalue_from_python_stage1_data *data) {
			const wchar_t *value = PyUnicode_AsUnicode(object);
			const std::wstring value_ws(value);
			if (value == 0) throw_error_already_set();
			void *storage = (
					(boost::python::converter::rvalue_from_python_storage<T> *)
							data)->storage.bytes;
			new(storage) T(fn(std::string(value_ws.begin(), value_ws.end())));
			data->convertible = storage;
		}

		static F fn;
	};

	template<typename F>
	struct to_str_wrapper {
		static F fn;

		std::string str(T &x) {
			return fn(x);
		}
	};

	template<typename F1, typename F2>
	static void wrap(const char *type_name, F1 to_str_fn, F2 from_str_fn) {
		from_pystring_converter<F2>::fn = from_str_fn;
		from_pystring_converter<F2>();
		to_str_wrapper<F1>::fn = to_str_fn;
		class_<T>(type_name, no_init).def("__str__", to_str_wrapper<F1>::str);
	};
};

std::string parse_python_exception();

template<typename Tn>
void python_export_global(const char *name, Tn &x) {
	PyObject * m, *d;
	m = PyImport_AddModule("__main__");
	if (m == NULL)
		return;
	d = PyModule_GetDict(m);
	try {
		PyObject * p = incref(object(boost::ref(x)).ptr());
		PyDict_SetItemString(d, name, p);
	} catch (boost::python::error_already_set const &) {
		// Parse and output the exception
		std::string perror_str = parse_python_exception();
		std::cout << "Error in Python: " << perror_str << std::endl;
		std::terminate();
	}
};

void init_python(const char *executable);

void deinit_python();

void execute_python_file(const char *python_file);

std::string parse_python_exception();

void arch_appendinittab();

#endif /* end of include guard: COMMON_PYBINDINGS_HH */