Skip to content

Rust bindings for qclib #5

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

bwalk-at-ibm
Copy link

This pull request adds bindings for the Rust programming language.

The second patch with examples is optional but provides usage example for the bindings by reimplementing zhypinfo and zname in Rust.

Ok(LayerCategory::from_raw(category))
}

impl_attr!(layer_name() -> String = LayerName);
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Stefan-Raspl: according to the qclib docs, qc_layer_name is only not available for KVM hypervisors. Is this an oversight in the documentation? If it is available for all layers, I make this a common attribute like the ones above.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you point at the exact piece of documentation with that statement?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's missing in the available attributes for KVM hypervisors.

Rust bindings implement an FFI interface to the qclib C library and
allows the usage of qclib in Rust context.

The bindings come in two crates:

    * qclib-sys: contains the raw FFI interface to the C library.
    * qclib: contains a safe and idiomatic abstraction for data types
      and functions provided by the C library.

Signed-off-by: Bjoern Walk <[email protected]>
Add native Rust implementations of zhypinfo and zname as an example for
the usage of the bindings.

Signed-off-by: Bjoern Walk <[email protected]>
Comment on lines +55 to +57
if rc < 0 {
return Err(Error { code: rc });
}
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll add handling rc > 0 as well (occurs when no consistent data is available after migration).


[package]
name = "qclib"
version = "2.0.0"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the significance of "version"? Should this reflect the actual package's version?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the version of the rust crate (library). I had it aligned with the version of the C library, but this will get awkward if we have changes in the crate and release a new version while the C library has not changed. I commented here before changing it. I'm open to suggestions since I'm not sure what the best handling is.

@@ -0,0 +1,22 @@
[workspace.package]
edition = "2021"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this the year of the code?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, it's the Rust edition (think C standard revisions like C89, C11 and so on) used for this crate.

@@ -0,0 +1 @@
../../LICENSE
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use a symlink instead? I assume Rust strictly requires a license file..?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is one :)

Yes, to publish the crate Rust requires an explicit license.

qc: self.qc,
layer: self.layer,
}),
LayerType::LparGroup => todo!(),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So this would be essentially a preview or beta version..?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you prefer, sure. I just implemented what I needed. The other layers should be trivial to implement but I don't have a testing environment available, so I left them out.

I can implement the rest or we could change the version to -beta, let me know what you prefer.

#![allow(nonstandard_style)]

pub type qc_layer_type = ::std::os::raw::c_uint;
pub const QC_LAYER_TYPE_CEC: qc_layer_type = 1;
Copy link
Contributor

@Stefan-Raspl Stefan-Raspl Jul 13, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't feel too well with these re-defines. Are these really necessary? I would have assumed all it takes is a couple 'extern "C"' wrapped functions, no?!
At the very least, we should look into automating the generation of these as part of the build procedure.

Copy link
Author

@bwalk-at-ibm bwalk-at-ibm Jul 13, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What are you worried about?

Yes, this file can be created automatically via bindgen (which in fact I didtried, but the results were suboptimal). I didn't want to mess with the build scripts for qclib, but I can look into it if you prefer.

I need the type definitions and their corresponding values in Rust context, I don't see a way around them.

map: &mut serde_json::Map<String, serde_json::Value>,
) -> Result<()> {
json_pair!(map <- Manufacturer: string? = self.manufacturer()?);
json_pair!(map <- Type: string? = self.machine_type()?);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might be my lack of knowledge of Rust: This is for generating json output? We already have routines in qclib - why re-implement?!

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it's for JSON output. The qc_export_json function that qclib provides dumps the JSON content to stdout and doesn't give the user any control over that.

I want to give the user more control, so I just create a JSON object and return that, allowing the user to process that how they prefer. It's done via a defacto standard dependencies for JSON handling and deserialization.

let mut rc = 0;
let layers = unsafe { sys::qc_get_num_layers(self.as_raw(), &mut rc) };

if rc < 0 {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I got this right, we're calling the C version of get_num_layers() here, but still check return codes. Why would we want to do that - to better the C version of the code...?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand, why wouldn't we check the return code? We are calling into the raw C function, so we need to check rc.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants