How to CStr to c_char slize

Hi,
i am trying myself in porting a C-interface to #[no_std] Rust.

Some of the C-Structs look like this:

const MAX_SIZE_9: usize = 9;
#[repr(C)]
pub struct FromC9 {
    pub foo: [c_char; MAX_SIZE_9], 
}

const MAX_SIZE_10: usize = 10;
#[repr(C)]
pub struct FromC10 {
    pub foo: [c_char; MAX_SIZE_10], 
}

I only need to construct these and pass them to the Caller.
Currently, I found a way by writing multiple conversion functions for CStr that addditionally care about the length constraints.

pub const fn c_string_as_i8_slice_9(input: &CStr) -> [c_char;MAX_SIZE_9] {
    let mut output: [c_char;MAX_SIZE_9] = [0;MAX_SIZE_9];
    let count = input.count_bytes();
    let usable_len = output.len()-1;
    let loop_len = if count < usable_len{
        count
    }else{
        usable_len
    };
    let bytes = input.to_bytes();
    let mut index=0;
    while index < loop_len{
        output[index]=bytes[index] as c_char;
        index = index +1;
    }
    output
}
pub const fn c_string_as_i8_slice_10(input: &CStr) -> [c_char;MAX_SIZE_10] {
    let mut output: [c_char;MAX_SIZE_10] = [0;MAX_SIZE_10];
    let count = input.count_bytes();
    let usable_len = output.len()-1;
    let loop_len = if count < usable_len{
        count
    }else{
        usable_len
    };
    let bytes = input.to_bytes();
    let mut index=0;
    while index < loop_len{
        output[index]=bytes[index] as c_char;
        index = index +1;
    }
    output
}

So my initialisation looks like this:

let foo = FromC9{
   foo = c_string_as_i8_slice_9(c"foo");
}

let bar = FromC10{
   foo = c_string_as_i8_slice_10(c"foo");
}

Is there a more generic way to solve this? I have to handle some more lengths :frowning:
Heap allocation is not possible. And I would prefer a solution during compile time.

Thanks for having a look!

You can use const generics:

pub const fn c_string_as_i8_slice<const MAX_SIZE: usize>(
    input: &CStr,
) -> [c_char; MAX_SIZE] {
    let mut output: [c_char; MAX_SIZE] = [0; MAX_SIZE];
    let count = input.count_bytes();
    let usable_len = output.len() - 1;
    let loop_len = if count < usable_len { count } else { usable_len };
    let bytes = input.to_bytes();
    let mut index = 0;
    while index < loop_len {
        output[index] = bytes[index] as c_char;
        index = index + 1;
    }
    output
}
let foo = FromC9 { foo: c_string_as_i8_slice::<MAX_SIZE_9>(c"foo") };
let bar = FromC10 { foo: c_string_as_i8_slice::<MAX_SIZE_10>(c"foo") };

And in this case the compiler can infer MAX_SIZE:

let foo = FromC9 { foo: c_string_as_i8_slice(c"foo") };
let bar = FromC10 { foo: c_string_as_i8_slice(c"foo") };
2 Likes

thank you very much!

1 Like