2323#include < nanobind/stl/vector.h> // NOLINT(misc-include-cleaner)
2424#include < qdmi/client.h>
2525
26+ #include < cstddef>
2627#include < optional>
2728#include < string>
2829#include < utility>
@@ -33,6 +34,44 @@ namespace mqt {
3334namespace nb = nanobind;
3435using namespace nb ::literals;
3536
37+ namespace {
38+ template <typename Query>
39+ [[nodiscard]] nb::object queryCustomValue (Query query,
40+ const nb::handle valueType) {
41+ const auto returnValue =
42+ []<typename T>(std::optional<T> value) -> nb::object {
43+ if (!value.has_value ()) {
44+ return nb::none ();
45+ }
46+ return nb::cast (std::move (*value));
47+ };
48+
49+ const auto builtins = nb::builtins ();
50+ if (valueType.is (builtins[" str" ])) {
51+ return returnValue (query.template operator ()<std::string>());
52+ }
53+ if (valueType.is (builtins[" bool" ])) {
54+ return returnValue (query.template operator ()<bool >());
55+ }
56+ if (valueType.is (builtins[" int" ])) {
57+ return returnValue (query.template operator ()<int >());
58+ }
59+ if (valueType.is (builtins[" float" ])) {
60+ return returnValue (query.template operator ()<double >());
61+ }
62+ if (valueType.is (builtins[" bytes" ])) {
63+ const auto value = query.template operator ()<std::vector<std::byte>>();
64+ if (!value.has_value ()) {
65+ return nb::none ();
66+ }
67+ return nb::bytes (reinterpret_cast <const char *>(value->data ()),
68+ value->size ());
69+ }
70+ throw nb::type_error (
71+ " value_type must be exactly str, bool, int, float, or bytes" );
72+ }
73+ } // namespace
74+
3675NB_MODULE (MQT_CORE_MODULE_NAME , m) {
3776 // Session class
3877 auto session = nb::class_<fomac::Session>(
@@ -157,6 +196,47 @@ All authentication parameters are optional and can be provided as keyword argume
157196 " Returns the sparse probabilities from the job (typically only "
158197 " available from simulator devices)." );
159198
199+ job.def (
200+ " query_custom_property" ,
201+ [](const fomac::Job& self, const fomac::CustomProperty customProperty,
202+ const nb::handle valueType) {
203+ return queryCustomValue (
204+ [&self, customProperty]<fomac::custom_property_value T>() {
205+ return self.queryCustomProperty <T>(customProperty);
206+ },
207+ valueType);
208+ },
209+ " custom_property" _a, " value_type" _a,
210+ nb::sig (" def query_custom_property(self, custom_property: "
211+ " CustomProperty, "
212+ " value_type: type[str] | type[bool] | type[int] | type[float] | "
213+ " type[bytes]) -> str | bool | int | float | bytes | None" ),
214+ R"pb( Query an implementation-defined custom job property.
215+
216+ The caller must provide the type documented by the device implementation.
217+ Use ``bytes`` to retrieve the value without interpretation. Returns ``None``
218+ when the custom slot is unsupported.)pb" );
219+
220+ job.def (
221+ " get_custom_result" ,
222+ [](const fomac::Job& self, const fomac::CustomProperty customProperty,
223+ const nb::handle valueType) {
224+ return queryCustomValue (
225+ [&self, customProperty]<fomac::custom_property_value T>() {
226+ return self.getCustomResult <T>(customProperty);
227+ },
228+ valueType);
229+ },
230+ " custom_property" _a, " value_type" _a,
231+ nb::sig (" def get_custom_result(self, custom_property: CustomProperty, "
232+ " value_type: type[str] | type[bool] | type[int] | type[float] | "
233+ " type[bytes]) -> str | bool | int | float | bytes | None" ),
234+ R"pb( Return an implementation-defined custom job result.
235+
236+ The caller must provide the type documented by the device implementation.
237+ Use ``bytes`` to retrieve the value without interpretation. Returns ``None``
238+ when the custom slot is unsupported.)pb" );
239+
160240 job.def_prop_ro (" id" , &fomac::Job::getId, " The job ID." );
161241
162242 job.def_prop_ro (" program_format" , &fomac::Job::getProgramFormat,
@@ -200,6 +280,15 @@ All authentication parameters are optional and can be provided as keyword argume
200280 .value (" CUSTOM4" , QDMI_PROGRAM_FORMAT_CUSTOM4 )
201281 .value (" CUSTOM5" , QDMI_PROGRAM_FORMAT_CUSTOM5 );
202282
283+ nb::enum_<fomac::CustomProperty>(
284+ m, " CustomProperty" ,
285+ " An implementation-defined custom property or result slot." )
286+ .value (" CUSTOM1" , fomac::CustomProperty::Custom1)
287+ .value (" CUSTOM2" , fomac::CustomProperty::Custom2)
288+ .value (" CUSTOM3" , fomac::CustomProperty::Custom3)
289+ .value (" CUSTOM4" , fomac::CustomProperty::Custom4)
290+ .value (" CUSTOM5" , fomac::CustomProperty::Custom5);
291+
203292 // Device class
204293 auto device = nb::class_<fomac::Device>(
205294 m, " Device" ,
@@ -270,6 +359,27 @@ All authentication parameters are optional and can be provided as keyword argume
270359 &fomac::Device::getSupportedProgramFormats,
271360 " Returns the list of program formats supported by the device." );
272361
362+ device.def (
363+ " query_custom_property" ,
364+ [](const fomac::Device& self, const fomac::CustomProperty customProperty,
365+ const nb::handle valueType) {
366+ return queryCustomValue (
367+ [&self, customProperty]<fomac::custom_property_value T>() {
368+ return self.queryCustomProperty <T>(customProperty);
369+ },
370+ valueType);
371+ },
372+ " custom_property" _a, " value_type" _a,
373+ nb::sig (" def query_custom_property(self, custom_property: "
374+ " CustomProperty, "
375+ " value_type: type[str] | type[bool] | type[int] | type[float] | "
376+ " type[bytes]) -> str | bool | int | float | bytes | None" ),
377+ R"pb( Query an implementation-defined custom device property.
378+
379+ The caller must provide the type documented by the device implementation.
380+ Use ``bytes`` to retrieve the value without interpretation. Returns ``None``
381+ when the custom slot is unsupported.)pb" );
382+
273383 device.def (" submit_job" , &fomac::Device::submitJob, " program" _a,
274384 " program_format" _a, " num_shots" _a, nb::kw_only (),
275385 " custom1" _a = nb::none (), " custom2" _a = nb::none (),
@@ -328,6 +438,27 @@ All authentication parameters are optional and can be provided as keyword argume
328438 site.def (" submodule_index" , &fomac::Site::getSubmoduleIndex,
329439 " Returns the index of the submodule the site belongs to." );
330440
441+ site.def (
442+ " query_custom_property" ,
443+ [](const fomac::Site& self, const fomac::CustomProperty customProperty,
444+ const nb::handle valueType) {
445+ return queryCustomValue (
446+ [&self, customProperty]<fomac::custom_property_value T>() {
447+ return self.queryCustomProperty <T>(customProperty);
448+ },
449+ valueType);
450+ },
451+ " custom_property" _a, " value_type" _a,
452+ nb::sig (" def query_custom_property(self, custom_property: "
453+ " CustomProperty, "
454+ " value_type: type[str] | type[bool] | type[int] | type[float] | "
455+ " type[bytes]) -> str | bool | int | float | bytes | None" ),
456+ R"pb( Query an implementation-defined custom site property.
457+
458+ The caller must provide the type documented by the device implementation.
459+ Use ``bytes`` to retrieve the value without interpretation. Returns ``None``
460+ when the custom slot is unsupported.)pb" );
461+
331462 site.def (" __repr__" , [](const fomac::Site& s) {
332463 return " <Site index=" + std::to_string (s.getIndex ()) + " >" ;
333464 });
@@ -399,6 +530,34 @@ All authentication parameters are optional and can be provided as keyword argume
399530 " params" _a.sig (" ..." ) = std::vector<double >{},
400531 " Returns the mean shuttling speed of the operation." );
401532
533+ operation.def (
534+ " query_custom_property" ,
535+ [](const fomac::Operation& self,
536+ const fomac::CustomProperty customProperty, const nb::handle valueType,
537+ const std::vector<fomac::Site>& sites,
538+ const std::vector<double >& params) {
539+ return queryCustomValue (
540+ [&self, customProperty, &sites,
541+ ¶ms]<fomac::custom_property_value T>() {
542+ return self.queryCustomProperty <T>(customProperty, sites, params);
543+ },
544+ valueType);
545+ },
546+ " custom_property" _a, " value_type" _a,
547+ " sites" _a.sig (" ..." ) = std::vector<fomac::Site>{},
548+ " params" _a.sig (" ..." ) = std::vector<double >{},
549+ nb::sig (" def query_custom_property(self, custom_property: "
550+ " CustomProperty, "
551+ " value_type: type[str] | type[bool] | type[int] | type[float] | "
552+ " type[bytes], sites: Sequence[mqt.core.fomac.Device.Site] = "
553+ " ..., params: Sequence[float] = ...) -> str | bool | int | "
554+ " float | bytes | None" ),
555+ R"pb( Query an implementation-defined custom operation property.
556+
557+ The caller must provide the type documented by the device implementation.
558+ Use ``bytes`` to retrieve the value without interpretation. Returns ``None``
559+ when the custom slot is unsupported.)pb" );
560+
402561 operation.def (" __repr__" , [](const fomac::Operation& op) {
403562 return " <Operation name=\" " + op.getName () + " \" >" ;
404563 });
0 commit comments