Skip to content
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

Lack of support of ENUM for C #419

Open
stephan57160 opened this issue May 10, 2022 · 8 comments
Open

Lack of support of ENUM for C #419

stephan57160 opened this issue May 10, 2022 · 8 comments
Labels
C++ C++ only related issues enhancement

Comments

@stephan57160
Copy link
Contributor

I figured out that .hpp is generated to expose constants for enums, but this file is not usable for pure C code.

I worked a bit on that, this afternoon.
I come to a c_<enum_name>.h that I'm able to include in a simple C code.
But, its also a bit redundant with the already generated <enum_name>.hpp.

I'd like to discuss this, before raising a PR.

@Dushistov Dushistov added enhancement C++ C++ only related issues labels May 10, 2022
@Dushistov
Copy link
Owner

This issue is mainly due to the fact that size of "C enum" is an implementation defined according to the C standard.
So generated "C API" get and return integers instead of enum, and C++ convert it from/into enum.
So while flapigen can generate "C enum" it is useless because of C functions should get/return fixed size integers anyway.

@Dushistov
Copy link
Owner

It is obviously possible to generate C inline function that wrap C functions and take care of conversions enum<->integer,
but this looks like overkill.

@stephan57160
Copy link
Contributor Author

Agreed for the enum returned by C.
The current C++ implemantation is rather similar to what could be done for C :

enum FOO {
   FOO_xxx = 0,
   FOO_yyy = 1,
   ...
};

It's also convenient, as RUST can convert ENUM to any INT.
It's not true from INT to ENUM, though.

@stephan57160
Copy link
Contributor Author

stephan57160 commented May 10, 2022

At least, this solves the situation where a RUST function returns an Error :

fn MyRustFunction() -> Error {...}

and the C code performs a switch ... case on returned value :

ret = MyRustFunction();
switch (ret) {
  case xxx : 
  ...
}

@stephan57160
Copy link
Contributor Author

Hmm ...
I may need some guidance, to write some test case(s), if you don't mind, for a PR.

@Dushistov
Copy link
Owner

The creation of expectation test would be rather simple.

  1. Create file in "macroslib/tests/expectations", for example "macroslib/tests/expectations/cenum.rs".
  2. Add this file into "macroslib/tests/expectations/tests.list"
  3. Add code that would process flapigen into cenum.rs, for example foreign_enum!(enum Boo { A = Boo::A, B = Boo::B });
  4. Add cenum.cpp file near cenum.rs, with C code that you expect to flapigen generate,
    in form of string literals separated by ";"
  5. Run cargo test --release, "release" because of debug build to slow.

In spite of name fenum.cpp may contains C and C++

@stephan57160
Copy link
Contributor Author

OK. Thx. I'll have a look this afternoon.

@stephan57160
Copy link
Contributor Author

From glue.rs.in code below :

foreign_enum!(
    enum SomeEnum {
        Val1                   = SomeEnum::Val1,
        Val2                   = SomeEnum::Val2,
        Val3                   = SomeEnum::Val3,
    }
);

foreign_class!(class Foo {
    fn return_is_enum() -> SomeEnum;
    fn param_is_enum(e: SomeEnum);
    fn param_and_return_are_enum(e: SomeEnum) -> SomeEnum;
});

I'm able to generate something like :

enum SomeEnum {
	SomeEnum_Val1 = 0,
	SomeEnum_Val2 = 1,
	SomeEnum_Val3 = 2,
};

typedef enum SomeEnum SomeEnumOpaque;

This part could be considered as complet :-)

Now, I wanted the C functions to use this new type.
So, I wandered in flapigen code and ...

OK. I suppose that the following generated code

    uint32_t Foo_return_is_enum();
    void Foo_param_is_enum(uint32_t e);
    uint32_t Foo_param_and_return_are_enum(uint32_t e);

is generated by RUSTC itself, based on cpp_glue.rs:

#[allow(non_snake_case, unused_variables, unused_mut, unused_unsafe)]
#[no_mangle]
pub extern "C" fn Foo_return_is_enum() -> u32 {
    let mut ret: SomeEnum = return_is_enum();
    let mut ret: u32 = <u32>::swig_from(ret);
    ret
}
...

Now, I understand your statment It is obviously possible to generate C inline function that wrap C functions and take care of conversions enum<->integer, but this looks like overkill....

Then ... I guess that there is no way to have something like

    SomeEnumOpaque Foo_return_is_enum();
    void Foo_param_is_enum(SomeEnumOpaque e);
    SomeEnumOpaque Foo_param_and_return_are_enum(SomeEnumOpaque e);

Moreover, I found that the C code is also used by the C++ one, to complicate a bit :-)
OK. I'll leave the function part there.

Then, I also had a look to tests/expectations.
It's rather simple to use.
I was able to get some test with it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
C++ C++ only related issues enhancement
Projects
None yet
Development

No branches or pull requests

2 participants