diff --git a/include/revng/PipeboxCommon/Helpers/Python/Casters.h b/include/revng/PipeboxCommon/Helpers/Python/Casters.h index 80f68d3ca..1ba64bfa9 100644 --- a/include/revng/PipeboxCommon/Helpers/Python/Casters.h +++ b/include/revng/PipeboxCommon/Helpers/Python/Casters.h @@ -69,6 +69,18 @@ struct type_caster { } }; +/// This is a caster class for bytes +template<> +struct type_caster> { + NB_TYPE_CASTER(llvm::ArrayRef, const_name("bytes")) + + bool from_python(handle Source, uint8_t, cleanup_list *) { + auto Bytes = nanobind::cast(Source); + value = { reinterpret_cast(Bytes.data()), Bytes.size() }; + return true; + } +}; + namespace detail { inline void llvmErrorToPythonException(llvm::Error &&Error) { diff --git a/include/revng/PipeboxCommon/Model.h b/include/revng/PipeboxCommon/Model.h index 674475866..23b5e960d 100644 --- a/include/revng/PipeboxCommon/Model.h +++ b/include/revng/PipeboxCommon/Model.h @@ -50,13 +50,16 @@ public: return Out; } - llvm::Error deserialize(llvm::StringRef Input) { - auto MaybeModel = TupleTree::fromString(Input); + static llvm::Expected deserialize(llvm::ArrayRef Input) { + llvm::StringRef String{ reinterpret_cast(Input.data()), + Input.size() }; + auto MaybeModel = TupleTree::fromString(String); if (not MaybeModel) return MaybeModel.takeError(); - TheModel = std::move(*MaybeModel); - return llvm::Error::success(); + Model Result; + Result.TheModel = std::move(*MaybeModel); + return Result; } public: diff --git a/lib/PipeboxCommon/Python/_pipebox.cpp b/lib/PipeboxCommon/Python/_pipebox.cpp index 6fc7dd155..232af270f 100644 --- a/lib/PipeboxCommon/Python/_pipebox.cpp +++ b/lib/PipeboxCommon/Python/_pipebox.cpp @@ -100,7 +100,7 @@ NB_MODULE(_pipebox, m) { }) .def("clone", &Model::clone) .def("serialize", &Model::serialize) - .def("deserialize", &Model::deserialize); + .def_static("deserialize", &Model::deserialize); // Register all Pipes, Analyses and Containers BaseClasses BC{ diff --git a/python/revng/pypeline/cli/pipeline/run_analysis.py b/python/revng/pypeline/cli/pipeline/run_analysis.py index 787d17c3c..5e629b163 100644 --- a/python/revng/pypeline/cli/pipeline/run_analysis.py +++ b/python/revng/pypeline/cli/pipeline/run_analysis.py @@ -131,9 +131,8 @@ def build_run_analysis_command( name=analysis_name, ) # Load the model - loaded_model: Model = model_ty() with open(model, "rb") as model_file: - loaded_model.deserialize(model_file.read()) + loaded_model = model_ty.deserialize(model_file.read()) logger.debug("Model loaded: `%s`", loaded_model) diff --git a/python/revng/pypeline/cli/pipeline/run_pipe.py b/python/revng/pypeline/cli/pipeline/run_pipe.py index bcde29c12..08954791f 100644 --- a/python/revng/pypeline/cli/pipeline/run_pipe.py +++ b/python/revng/pypeline/cli/pipeline/run_pipe.py @@ -154,9 +154,8 @@ def build_pipe_command( static_configuration=static_configuration, ) # Load the model - loaded_model: Model = model_ty() with open(model, "rb") as model_file: - loaded_model.deserialize(model_file.read()) + loaded_model = model_ty.deserialize(model_file.read()) # Load the containers with args form the command line containers = [] for arg in pipe.arguments: diff --git a/python/revng/pypeline/cli/project/analyze.py b/python/revng/pypeline/cli/project/analyze.py index 1f439d555..85a2135ba 100644 --- a/python/revng/pypeline/cli/project/analyze.py +++ b/python/revng/pypeline/cli/project/analyze.py @@ -117,8 +117,7 @@ def build_analysis_command( # Load the model storage_provider = storage_provider_factory(model_path=model) - loaded_model: Model = model_ty() - loaded_model.deserialize(storage_provider.get_model()) + loaded_model = model_ty.deserialize(storage_provider.get_model()) logger.debug("Model loaded: `%s`", loaded_model) diff --git a/python/revng/pypeline/cli/project/artifact.py b/python/revng/pypeline/cli/project/artifact.py index 6def537f7..2245003bc 100644 --- a/python/revng/pypeline/cli/project/artifact.py +++ b/python/revng/pypeline/cli/project/artifact.py @@ -128,8 +128,7 @@ def build_artifact_command( # Load the model storage_provider = storage_provider_factory(model_path=model) - loaded_model: Model = model_ty() - loaded_model.deserialize(storage_provider.get_model()) + loaded_model = model_ty.deserialize(storage_provider.get_model()) logger.debug("Model loaded: `%s`", loaded_model) diff --git a/python/revng/pypeline/model.py b/python/revng/pypeline/model.py index 419ff9084..ef8ac057f 100644 --- a/python/revng/pypeline/model.py +++ b/python/revng/pypeline/model.py @@ -103,8 +103,9 @@ class Model(ABC): def serialize(self) -> bytes: pass + @classmethod @abstractmethod - def deserialize(self, data: bytes): + def deserialize(cls, data: bytes) -> Model: pass @classmethod diff --git a/tests/pypeline/simple_pipeline.py b/tests/pypeline/simple_pipeline.py index 64c973015..3f62cac50 100644 --- a/tests/pypeline/simple_pipeline.py +++ b/tests/pypeline/simple_pipeline.py @@ -296,8 +296,11 @@ class DictModel(Model): def serialize(self): return yaml.safe_dump(self._data).encode() - def deserialize(self, data: bytes): - self._data = yaml.safe_load(data) + @classmethod + def deserialize(cls, data: bytes): + result = DictModel() + result._data = yaml.safe_load(data) + return result def __repr__(self): return f"DictModel({self._data!r})" diff --git a/tests/pypeline/test_all.py b/tests/pypeline/test_all.py index 0217fe008..5f3f01ed0 100644 --- a/tests/pypeline/test_all.py +++ b/tests/pypeline/test_all.py @@ -531,9 +531,8 @@ def test_pipeline(storage_provider): pipeline = load_pipeline_yaml_file(os.path.join(root, "pipeline.yml")) pipeline_configuration: PipelineConfiguration = {} - model = DictModel() with open(os.path.join(root, "model.yml"), "rb") as model_file: - model.deserialize(model_file.read()) + model = DictModel.deserialize(model_file.read()) res = pipeline.get_artifact( model=ReadOnlyModel(model), diff --git a/tools/pypeline-trace-run/Main.cpp b/tools/pypeline-trace-run/Main.cpp index a5ff89bc6..23424f633 100644 --- a/tools/pypeline-trace-run/Main.cpp +++ b/tools/pypeline-trace-run/Main.cpp @@ -42,8 +42,8 @@ int main(int Argc, const char *Argv[]) { TraceFile Trace = AbortOnError(TraceFile::fromFile(Options::TraceFile)); auto ModelBuffer = revng::cantFail(MemoryBuffer::getFile(Options::ModelFile)); - Model TheModel; - AbortOnError(TheModel.deserialize(ModelBuffer->getBuffer())); + auto BufferRef = llvm::arrayRefFromStringRef(ModelBuffer->getBuffer()); + Model TheModel = AbortOnError(Model::deserialize(BufferRef)); SavePoint SP(Options::StorageFile);