How to convert Vec<Rgb> to Vec









up vote
2
down vote

favorite
1












Using the Piston image crate, I can write an image by feeding it a Vec<u8>, but my actual data is Vec<Rgb<u8>> (because that is a lot easier to deal with, and I want to grow it dynamically).



How can I convert Vec<Rgb<u8>> to Vec<u8>? Rgb<u8> is really [u8; 3]. Does this have to be an unsafe conversion?










share|improve this question

















  • 1




    What does conversion mean in this case? What is the converted value of vec![[10, 20, 30], [5, 15, 25]]?
    – trentcl
    Nov 8 at 18:10






  • 2




    @trentcl I'm assuming flattened.
    – Shepmaster
    Nov 8 at 18:11










  • Well, to go the other way, I'd do it with .chunks(3), so I assume you could use .map(|x| x.iter()).flatten()
    – Optimistic Peach
    Nov 8 at 19:13














up vote
2
down vote

favorite
1












Using the Piston image crate, I can write an image by feeding it a Vec<u8>, but my actual data is Vec<Rgb<u8>> (because that is a lot easier to deal with, and I want to grow it dynamically).



How can I convert Vec<Rgb<u8>> to Vec<u8>? Rgb<u8> is really [u8; 3]. Does this have to be an unsafe conversion?










share|improve this question

















  • 1




    What does conversion mean in this case? What is the converted value of vec![[10, 20, 30], [5, 15, 25]]?
    – trentcl
    Nov 8 at 18:10






  • 2




    @trentcl I'm assuming flattened.
    – Shepmaster
    Nov 8 at 18:11










  • Well, to go the other way, I'd do it with .chunks(3), so I assume you could use .map(|x| x.iter()).flatten()
    – Optimistic Peach
    Nov 8 at 19:13












up vote
2
down vote

favorite
1









up vote
2
down vote

favorite
1






1





Using the Piston image crate, I can write an image by feeding it a Vec<u8>, but my actual data is Vec<Rgb<u8>> (because that is a lot easier to deal with, and I want to grow it dynamically).



How can I convert Vec<Rgb<u8>> to Vec<u8>? Rgb<u8> is really [u8; 3]. Does this have to be an unsafe conversion?










share|improve this question













Using the Piston image crate, I can write an image by feeding it a Vec<u8>, but my actual data is Vec<Rgb<u8>> (because that is a lot easier to deal with, and I want to grow it dynamically).



How can I convert Vec<Rgb<u8>> to Vec<u8>? Rgb<u8> is really [u8; 3]. Does this have to be an unsafe conversion?







rust rust-piston






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked Nov 8 at 17:20









Timmmm

35.4k28189245




35.4k28189245







  • 1




    What does conversion mean in this case? What is the converted value of vec![[10, 20, 30], [5, 15, 25]]?
    – trentcl
    Nov 8 at 18:10






  • 2




    @trentcl I'm assuming flattened.
    – Shepmaster
    Nov 8 at 18:11










  • Well, to go the other way, I'd do it with .chunks(3), so I assume you could use .map(|x| x.iter()).flatten()
    – Optimistic Peach
    Nov 8 at 19:13












  • 1




    What does conversion mean in this case? What is the converted value of vec![[10, 20, 30], [5, 15, 25]]?
    – trentcl
    Nov 8 at 18:10






  • 2




    @trentcl I'm assuming flattened.
    – Shepmaster
    Nov 8 at 18:11










  • Well, to go the other way, I'd do it with .chunks(3), so I assume you could use .map(|x| x.iter()).flatten()
    – Optimistic Peach
    Nov 8 at 19:13







1




1




What does conversion mean in this case? What is the converted value of vec![[10, 20, 30], [5, 15, 25]]?
– trentcl
Nov 8 at 18:10




What does conversion mean in this case? What is the converted value of vec![[10, 20, 30], [5, 15, 25]]?
– trentcl
Nov 8 at 18:10




2




2




@trentcl I'm assuming flattened.
– Shepmaster
Nov 8 at 18:11




@trentcl I'm assuming flattened.
– Shepmaster
Nov 8 at 18:11












Well, to go the other way, I'd do it with .chunks(3), so I assume you could use .map(|x| x.iter()).flatten()
– Optimistic Peach
Nov 8 at 19:13




Well, to go the other way, I'd do it with .chunks(3), so I assume you could use .map(|x| x.iter()).flatten()
– Optimistic Peach
Nov 8 at 19:13












2 Answers
2






active

oldest

votes

















up vote
6
down vote



accepted










The answer depends on whether you are fine with copying the data. If copying is not an issue for you, you can do something like this:



let img: Vec<Rgb<u8>> = ...;
let buf: Vec<u8> = img.iter().flat_map(|rgb| rgb.data.iter()).cloned().collect();


If you want to perform the conversion without copying, though, we first need to make sure that your source and destination types actually have the same memory layout. Rust makes very few guarantees about the memory layout of structs. It currently does not even guarantee that a struct with a single member has the same memory layout as the member itself.



In this particular case, the Rust memory layout is not relevant though, since Rgb is defined as



#[repr(C)]
pub struct Rgb<T: Primitive>
pub data: [T; 3],



The #[repr(C)] attribute specifies that the memory layout of the struct should be the same as an equivalent C struct. The C memory layout is not fully specified in the C standard, but according to the unsafe code guidelines, there are some rules that hold for "most" platforms:




  • Field order is preserved.

  • The first field begins at offset 0.

  • Assuming the struct is not packed, each field's offset is aligned to the ABI-mandated alignment for that field's type, possibly creating unused padding bits.

  • The total size of the struct is rounded up to its overall alignment.



As pointed out in the comments, the C standard theoretically allows additional padding at the end of the struct. However, the Piston image library itself makes the assumption that a slice of channel data has the same memory layout as the Rgb struct, so if you are on a platform where this assumption does not hold, all bets are off anyway (and I couldnt' find any evidence that such a platform exists).



Rust does guarantee that arrays, slices and vectors are densely packed, and that structs and arrays have an alignment equal to the maximum alignment of their elements. Together with the assumption that the layout of Rgb is as specified by the rules I quotes above, this guarantees that Rgb<u8> is indeed laid out as three consecutive bytes in memory, and that Vec<Rgb<u8>> is indeed a consecutive, densely packed buffer of RGB values, so our conversion is safe. We still need to use unsafe code to write it:



let p = img.as_mut_ptr();
let len = img.len() * mem::size_of::<Rgb<u8>>();
let cap = img.capacity() * mem::size_of::<Rgb<u8>>();
mem::forget(img);
let buf: Vec<u8> = unsafe Vec::from_raw_parts(p as *mut u8, len, cap) ;


If you want to protect against the case that there is additional padding at the end of Rgb, you can check whether size_of::<Rgb<u8>>() is indeed 3. If it is, you can use the unsafe non-copying version, otherwise you have to use the first version above.






share|improve this answer


















  • 3




    The entire paragraph explaining why the programmer believes this to be safe should be a comment directly next to the unsafe block.
    – Shepmaster
    Nov 8 at 20:13






  • 1




    C doesn't guarantee anything about potential padding bytes at the end of such structure. A valid implementation can align data to 4 bytes for exemple. port70.net/~nsz/c/c11/n1570.html#6.7.2.1p14, port70.net/~nsz/c/c11/n1570.html#6.7.2.1p17, (C17 didn't change that). So #[repr(C)] doesn't change the problem. That very rare and unexpected but that exist on some embedded system.
    – Stargateur
    Nov 8 at 23:37











  • @Stargateur When I wrote the answer, I looked up the rules of repr(C) in the unsafe code guidelines – specifically "The total size of the struct is rounded up to its overall alignment." However, I missed that this is only valid for "most" platforms.
    – Sven Marnach
    Nov 9 at 9:10










  • @Stargateur While it's clear that the standard allows the additional padding, I'm not convinced that this can actually happen in practice. I tried to find evidence that there are targets that would actually add additional padding in this particular case, but couldn't find any. Do you have a link by any chance?
    – Sven Marnach
    Nov 9 at 9:31










  • Exemple (Of course, this use an extension for simplicity) but the idea is that the memory layout of struct data is valid according to C ISO, Rust and C doesn't give a lot of guarantee about memory layout. C have few guarantee however but not the one you need to say "this is safe in any implementation". ABI C is implemented defined, there is NOT one standard ABI in C. ABI is not even quoted in the ISO. People can assume anything but that doesn't concern C.
    – Stargateur
    Nov 9 at 10:24


















up vote
2
down vote













You choose the Vec<Rgb<u8>> storage format because it's easier to deal with and you want it to grow dynamically. But as you noticed, there's no guarantee of compatibility of its storage with a Vec<u8>, and no safe conversion.



Why not take the problem the other way and build a convenient facade for a Vec<u8> ?



type Rgb = [u8; 3];

#[derive(Debug)]
struct Img(Vec<u8>);

impl Img
fn new() -> Img
Img(Vec::new())


fn push(&mut self, rgb: &Rgb)
self.0.push(rgb[0]);
self.0.push(rgb[1]);
self.0.push(rgb[2]);


// other convenient methods


fn main()
let mut img = Img::new();
let rgb : Rgb = [1, 2, 3];
img.push(&rgb);
img.push(&rgb);
println!(":?", img);






share|improve this answer






















  • For what it's worth, the image library basically provides such a façade in the form of the ImageBuffer struct, so the right answer is probably to simply use that.
    – Sven Marnach
    Nov 9 at 10:20










  • I didn't use ImageBuffer because it has a fixed width & height and as I noted in the question I want to grow by Vec<> dynamically.
    – Timmmm
    Nov 9 at 11:13










Your Answer






StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");

StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "1"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);

else
createEditor();

);

function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);



);













 

draft saved


draft discarded


















StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53213025%2fhow-to-convert-vecrgbu8-to-vecu8%23new-answer', 'question_page');

);

Post as a guest






























2 Answers
2






active

oldest

votes








2 Answers
2






active

oldest

votes









active

oldest

votes






active

oldest

votes








up vote
6
down vote



accepted










The answer depends on whether you are fine with copying the data. If copying is not an issue for you, you can do something like this:



let img: Vec<Rgb<u8>> = ...;
let buf: Vec<u8> = img.iter().flat_map(|rgb| rgb.data.iter()).cloned().collect();


If you want to perform the conversion without copying, though, we first need to make sure that your source and destination types actually have the same memory layout. Rust makes very few guarantees about the memory layout of structs. It currently does not even guarantee that a struct with a single member has the same memory layout as the member itself.



In this particular case, the Rust memory layout is not relevant though, since Rgb is defined as



#[repr(C)]
pub struct Rgb<T: Primitive>
pub data: [T; 3],



The #[repr(C)] attribute specifies that the memory layout of the struct should be the same as an equivalent C struct. The C memory layout is not fully specified in the C standard, but according to the unsafe code guidelines, there are some rules that hold for "most" platforms:




  • Field order is preserved.

  • The first field begins at offset 0.

  • Assuming the struct is not packed, each field's offset is aligned to the ABI-mandated alignment for that field's type, possibly creating unused padding bits.

  • The total size of the struct is rounded up to its overall alignment.



As pointed out in the comments, the C standard theoretically allows additional padding at the end of the struct. However, the Piston image library itself makes the assumption that a slice of channel data has the same memory layout as the Rgb struct, so if you are on a platform where this assumption does not hold, all bets are off anyway (and I couldnt' find any evidence that such a platform exists).



Rust does guarantee that arrays, slices and vectors are densely packed, and that structs and arrays have an alignment equal to the maximum alignment of their elements. Together with the assumption that the layout of Rgb is as specified by the rules I quotes above, this guarantees that Rgb<u8> is indeed laid out as three consecutive bytes in memory, and that Vec<Rgb<u8>> is indeed a consecutive, densely packed buffer of RGB values, so our conversion is safe. We still need to use unsafe code to write it:



let p = img.as_mut_ptr();
let len = img.len() * mem::size_of::<Rgb<u8>>();
let cap = img.capacity() * mem::size_of::<Rgb<u8>>();
mem::forget(img);
let buf: Vec<u8> = unsafe Vec::from_raw_parts(p as *mut u8, len, cap) ;


If you want to protect against the case that there is additional padding at the end of Rgb, you can check whether size_of::<Rgb<u8>>() is indeed 3. If it is, you can use the unsafe non-copying version, otherwise you have to use the first version above.






share|improve this answer


















  • 3




    The entire paragraph explaining why the programmer believes this to be safe should be a comment directly next to the unsafe block.
    – Shepmaster
    Nov 8 at 20:13






  • 1




    C doesn't guarantee anything about potential padding bytes at the end of such structure. A valid implementation can align data to 4 bytes for exemple. port70.net/~nsz/c/c11/n1570.html#6.7.2.1p14, port70.net/~nsz/c/c11/n1570.html#6.7.2.1p17, (C17 didn't change that). So #[repr(C)] doesn't change the problem. That very rare and unexpected but that exist on some embedded system.
    – Stargateur
    Nov 8 at 23:37











  • @Stargateur When I wrote the answer, I looked up the rules of repr(C) in the unsafe code guidelines – specifically "The total size of the struct is rounded up to its overall alignment." However, I missed that this is only valid for "most" platforms.
    – Sven Marnach
    Nov 9 at 9:10










  • @Stargateur While it's clear that the standard allows the additional padding, I'm not convinced that this can actually happen in practice. I tried to find evidence that there are targets that would actually add additional padding in this particular case, but couldn't find any. Do you have a link by any chance?
    – Sven Marnach
    Nov 9 at 9:31










  • Exemple (Of course, this use an extension for simplicity) but the idea is that the memory layout of struct data is valid according to C ISO, Rust and C doesn't give a lot of guarantee about memory layout. C have few guarantee however but not the one you need to say "this is safe in any implementation". ABI C is implemented defined, there is NOT one standard ABI in C. ABI is not even quoted in the ISO. People can assume anything but that doesn't concern C.
    – Stargateur
    Nov 9 at 10:24















up vote
6
down vote



accepted










The answer depends on whether you are fine with copying the data. If copying is not an issue for you, you can do something like this:



let img: Vec<Rgb<u8>> = ...;
let buf: Vec<u8> = img.iter().flat_map(|rgb| rgb.data.iter()).cloned().collect();


If you want to perform the conversion without copying, though, we first need to make sure that your source and destination types actually have the same memory layout. Rust makes very few guarantees about the memory layout of structs. It currently does not even guarantee that a struct with a single member has the same memory layout as the member itself.



In this particular case, the Rust memory layout is not relevant though, since Rgb is defined as



#[repr(C)]
pub struct Rgb<T: Primitive>
pub data: [T; 3],



The #[repr(C)] attribute specifies that the memory layout of the struct should be the same as an equivalent C struct. The C memory layout is not fully specified in the C standard, but according to the unsafe code guidelines, there are some rules that hold for "most" platforms:




  • Field order is preserved.

  • The first field begins at offset 0.

  • Assuming the struct is not packed, each field's offset is aligned to the ABI-mandated alignment for that field's type, possibly creating unused padding bits.

  • The total size of the struct is rounded up to its overall alignment.



As pointed out in the comments, the C standard theoretically allows additional padding at the end of the struct. However, the Piston image library itself makes the assumption that a slice of channel data has the same memory layout as the Rgb struct, so if you are on a platform where this assumption does not hold, all bets are off anyway (and I couldnt' find any evidence that such a platform exists).



Rust does guarantee that arrays, slices and vectors are densely packed, and that structs and arrays have an alignment equal to the maximum alignment of their elements. Together with the assumption that the layout of Rgb is as specified by the rules I quotes above, this guarantees that Rgb<u8> is indeed laid out as three consecutive bytes in memory, and that Vec<Rgb<u8>> is indeed a consecutive, densely packed buffer of RGB values, so our conversion is safe. We still need to use unsafe code to write it:



let p = img.as_mut_ptr();
let len = img.len() * mem::size_of::<Rgb<u8>>();
let cap = img.capacity() * mem::size_of::<Rgb<u8>>();
mem::forget(img);
let buf: Vec<u8> = unsafe Vec::from_raw_parts(p as *mut u8, len, cap) ;


If you want to protect against the case that there is additional padding at the end of Rgb, you can check whether size_of::<Rgb<u8>>() is indeed 3. If it is, you can use the unsafe non-copying version, otherwise you have to use the first version above.






share|improve this answer


















  • 3




    The entire paragraph explaining why the programmer believes this to be safe should be a comment directly next to the unsafe block.
    – Shepmaster
    Nov 8 at 20:13






  • 1




    C doesn't guarantee anything about potential padding bytes at the end of such structure. A valid implementation can align data to 4 bytes for exemple. port70.net/~nsz/c/c11/n1570.html#6.7.2.1p14, port70.net/~nsz/c/c11/n1570.html#6.7.2.1p17, (C17 didn't change that). So #[repr(C)] doesn't change the problem. That very rare and unexpected but that exist on some embedded system.
    – Stargateur
    Nov 8 at 23:37











  • @Stargateur When I wrote the answer, I looked up the rules of repr(C) in the unsafe code guidelines – specifically "The total size of the struct is rounded up to its overall alignment." However, I missed that this is only valid for "most" platforms.
    – Sven Marnach
    Nov 9 at 9:10










  • @Stargateur While it's clear that the standard allows the additional padding, I'm not convinced that this can actually happen in practice. I tried to find evidence that there are targets that would actually add additional padding in this particular case, but couldn't find any. Do you have a link by any chance?
    – Sven Marnach
    Nov 9 at 9:31










  • Exemple (Of course, this use an extension for simplicity) but the idea is that the memory layout of struct data is valid according to C ISO, Rust and C doesn't give a lot of guarantee about memory layout. C have few guarantee however but not the one you need to say "this is safe in any implementation". ABI C is implemented defined, there is NOT one standard ABI in C. ABI is not even quoted in the ISO. People can assume anything but that doesn't concern C.
    – Stargateur
    Nov 9 at 10:24













up vote
6
down vote



accepted







up vote
6
down vote



accepted






The answer depends on whether you are fine with copying the data. If copying is not an issue for you, you can do something like this:



let img: Vec<Rgb<u8>> = ...;
let buf: Vec<u8> = img.iter().flat_map(|rgb| rgb.data.iter()).cloned().collect();


If you want to perform the conversion without copying, though, we first need to make sure that your source and destination types actually have the same memory layout. Rust makes very few guarantees about the memory layout of structs. It currently does not even guarantee that a struct with a single member has the same memory layout as the member itself.



In this particular case, the Rust memory layout is not relevant though, since Rgb is defined as



#[repr(C)]
pub struct Rgb<T: Primitive>
pub data: [T; 3],



The #[repr(C)] attribute specifies that the memory layout of the struct should be the same as an equivalent C struct. The C memory layout is not fully specified in the C standard, but according to the unsafe code guidelines, there are some rules that hold for "most" platforms:




  • Field order is preserved.

  • The first field begins at offset 0.

  • Assuming the struct is not packed, each field's offset is aligned to the ABI-mandated alignment for that field's type, possibly creating unused padding bits.

  • The total size of the struct is rounded up to its overall alignment.



As pointed out in the comments, the C standard theoretically allows additional padding at the end of the struct. However, the Piston image library itself makes the assumption that a slice of channel data has the same memory layout as the Rgb struct, so if you are on a platform where this assumption does not hold, all bets are off anyway (and I couldnt' find any evidence that such a platform exists).



Rust does guarantee that arrays, slices and vectors are densely packed, and that structs and arrays have an alignment equal to the maximum alignment of their elements. Together with the assumption that the layout of Rgb is as specified by the rules I quotes above, this guarantees that Rgb<u8> is indeed laid out as three consecutive bytes in memory, and that Vec<Rgb<u8>> is indeed a consecutive, densely packed buffer of RGB values, so our conversion is safe. We still need to use unsafe code to write it:



let p = img.as_mut_ptr();
let len = img.len() * mem::size_of::<Rgb<u8>>();
let cap = img.capacity() * mem::size_of::<Rgb<u8>>();
mem::forget(img);
let buf: Vec<u8> = unsafe Vec::from_raw_parts(p as *mut u8, len, cap) ;


If you want to protect against the case that there is additional padding at the end of Rgb, you can check whether size_of::<Rgb<u8>>() is indeed 3. If it is, you can use the unsafe non-copying version, otherwise you have to use the first version above.






share|improve this answer














The answer depends on whether you are fine with copying the data. If copying is not an issue for you, you can do something like this:



let img: Vec<Rgb<u8>> = ...;
let buf: Vec<u8> = img.iter().flat_map(|rgb| rgb.data.iter()).cloned().collect();


If you want to perform the conversion without copying, though, we first need to make sure that your source and destination types actually have the same memory layout. Rust makes very few guarantees about the memory layout of structs. It currently does not even guarantee that a struct with a single member has the same memory layout as the member itself.



In this particular case, the Rust memory layout is not relevant though, since Rgb is defined as



#[repr(C)]
pub struct Rgb<T: Primitive>
pub data: [T; 3],



The #[repr(C)] attribute specifies that the memory layout of the struct should be the same as an equivalent C struct. The C memory layout is not fully specified in the C standard, but according to the unsafe code guidelines, there are some rules that hold for "most" platforms:




  • Field order is preserved.

  • The first field begins at offset 0.

  • Assuming the struct is not packed, each field's offset is aligned to the ABI-mandated alignment for that field's type, possibly creating unused padding bits.

  • The total size of the struct is rounded up to its overall alignment.



As pointed out in the comments, the C standard theoretically allows additional padding at the end of the struct. However, the Piston image library itself makes the assumption that a slice of channel data has the same memory layout as the Rgb struct, so if you are on a platform where this assumption does not hold, all bets are off anyway (and I couldnt' find any evidence that such a platform exists).



Rust does guarantee that arrays, slices and vectors are densely packed, and that structs and arrays have an alignment equal to the maximum alignment of their elements. Together with the assumption that the layout of Rgb is as specified by the rules I quotes above, this guarantees that Rgb<u8> is indeed laid out as three consecutive bytes in memory, and that Vec<Rgb<u8>> is indeed a consecutive, densely packed buffer of RGB values, so our conversion is safe. We still need to use unsafe code to write it:



let p = img.as_mut_ptr();
let len = img.len() * mem::size_of::<Rgb<u8>>();
let cap = img.capacity() * mem::size_of::<Rgb<u8>>();
mem::forget(img);
let buf: Vec<u8> = unsafe Vec::from_raw_parts(p as *mut u8, len, cap) ;


If you want to protect against the case that there is additional padding at the end of Rgb, you can check whether size_of::<Rgb<u8>>() is indeed 3. If it is, you can use the unsafe non-copying version, otherwise you have to use the first version above.







share|improve this answer














share|improve this answer



share|improve this answer








edited Nov 9 at 13:03

























answered Nov 8 at 19:39









Sven Marnach

336k75737686




336k75737686







  • 3




    The entire paragraph explaining why the programmer believes this to be safe should be a comment directly next to the unsafe block.
    – Shepmaster
    Nov 8 at 20:13






  • 1




    C doesn't guarantee anything about potential padding bytes at the end of such structure. A valid implementation can align data to 4 bytes for exemple. port70.net/~nsz/c/c11/n1570.html#6.7.2.1p14, port70.net/~nsz/c/c11/n1570.html#6.7.2.1p17, (C17 didn't change that). So #[repr(C)] doesn't change the problem. That very rare and unexpected but that exist on some embedded system.
    – Stargateur
    Nov 8 at 23:37











  • @Stargateur When I wrote the answer, I looked up the rules of repr(C) in the unsafe code guidelines – specifically "The total size of the struct is rounded up to its overall alignment." However, I missed that this is only valid for "most" platforms.
    – Sven Marnach
    Nov 9 at 9:10










  • @Stargateur While it's clear that the standard allows the additional padding, I'm not convinced that this can actually happen in practice. I tried to find evidence that there are targets that would actually add additional padding in this particular case, but couldn't find any. Do you have a link by any chance?
    – Sven Marnach
    Nov 9 at 9:31










  • Exemple (Of course, this use an extension for simplicity) but the idea is that the memory layout of struct data is valid according to C ISO, Rust and C doesn't give a lot of guarantee about memory layout. C have few guarantee however but not the one you need to say "this is safe in any implementation". ABI C is implemented defined, there is NOT one standard ABI in C. ABI is not even quoted in the ISO. People can assume anything but that doesn't concern C.
    – Stargateur
    Nov 9 at 10:24













  • 3




    The entire paragraph explaining why the programmer believes this to be safe should be a comment directly next to the unsafe block.
    – Shepmaster
    Nov 8 at 20:13






  • 1




    C doesn't guarantee anything about potential padding bytes at the end of such structure. A valid implementation can align data to 4 bytes for exemple. port70.net/~nsz/c/c11/n1570.html#6.7.2.1p14, port70.net/~nsz/c/c11/n1570.html#6.7.2.1p17, (C17 didn't change that). So #[repr(C)] doesn't change the problem. That very rare and unexpected but that exist on some embedded system.
    – Stargateur
    Nov 8 at 23:37











  • @Stargateur When I wrote the answer, I looked up the rules of repr(C) in the unsafe code guidelines – specifically "The total size of the struct is rounded up to its overall alignment." However, I missed that this is only valid for "most" platforms.
    – Sven Marnach
    Nov 9 at 9:10










  • @Stargateur While it's clear that the standard allows the additional padding, I'm not convinced that this can actually happen in practice. I tried to find evidence that there are targets that would actually add additional padding in this particular case, but couldn't find any. Do you have a link by any chance?
    – Sven Marnach
    Nov 9 at 9:31










  • Exemple (Of course, this use an extension for simplicity) but the idea is that the memory layout of struct data is valid according to C ISO, Rust and C doesn't give a lot of guarantee about memory layout. C have few guarantee however but not the one you need to say "this is safe in any implementation". ABI C is implemented defined, there is NOT one standard ABI in C. ABI is not even quoted in the ISO. People can assume anything but that doesn't concern C.
    – Stargateur
    Nov 9 at 10:24








3




3




The entire paragraph explaining why the programmer believes this to be safe should be a comment directly next to the unsafe block.
– Shepmaster
Nov 8 at 20:13




The entire paragraph explaining why the programmer believes this to be safe should be a comment directly next to the unsafe block.
– Shepmaster
Nov 8 at 20:13




1




1




C doesn't guarantee anything about potential padding bytes at the end of such structure. A valid implementation can align data to 4 bytes for exemple. port70.net/~nsz/c/c11/n1570.html#6.7.2.1p14, port70.net/~nsz/c/c11/n1570.html#6.7.2.1p17, (C17 didn't change that). So #[repr(C)] doesn't change the problem. That very rare and unexpected but that exist on some embedded system.
– Stargateur
Nov 8 at 23:37





C doesn't guarantee anything about potential padding bytes at the end of such structure. A valid implementation can align data to 4 bytes for exemple. port70.net/~nsz/c/c11/n1570.html#6.7.2.1p14, port70.net/~nsz/c/c11/n1570.html#6.7.2.1p17, (C17 didn't change that). So #[repr(C)] doesn't change the problem. That very rare and unexpected but that exist on some embedded system.
– Stargateur
Nov 8 at 23:37













@Stargateur When I wrote the answer, I looked up the rules of repr(C) in the unsafe code guidelines – specifically "The total size of the struct is rounded up to its overall alignment." However, I missed that this is only valid for "most" platforms.
– Sven Marnach
Nov 9 at 9:10




@Stargateur When I wrote the answer, I looked up the rules of repr(C) in the unsafe code guidelines – specifically "The total size of the struct is rounded up to its overall alignment." However, I missed that this is only valid for "most" platforms.
– Sven Marnach
Nov 9 at 9:10












@Stargateur While it's clear that the standard allows the additional padding, I'm not convinced that this can actually happen in practice. I tried to find evidence that there are targets that would actually add additional padding in this particular case, but couldn't find any. Do you have a link by any chance?
– Sven Marnach
Nov 9 at 9:31




@Stargateur While it's clear that the standard allows the additional padding, I'm not convinced that this can actually happen in practice. I tried to find evidence that there are targets that would actually add additional padding in this particular case, but couldn't find any. Do you have a link by any chance?
– Sven Marnach
Nov 9 at 9:31












Exemple (Of course, this use an extension for simplicity) but the idea is that the memory layout of struct data is valid according to C ISO, Rust and C doesn't give a lot of guarantee about memory layout. C have few guarantee however but not the one you need to say "this is safe in any implementation". ABI C is implemented defined, there is NOT one standard ABI in C. ABI is not even quoted in the ISO. People can assume anything but that doesn't concern C.
– Stargateur
Nov 9 at 10:24





Exemple (Of course, this use an extension for simplicity) but the idea is that the memory layout of struct data is valid according to C ISO, Rust and C doesn't give a lot of guarantee about memory layout. C have few guarantee however but not the one you need to say "this is safe in any implementation". ABI C is implemented defined, there is NOT one standard ABI in C. ABI is not even quoted in the ISO. People can assume anything but that doesn't concern C.
– Stargateur
Nov 9 at 10:24













up vote
2
down vote













You choose the Vec<Rgb<u8>> storage format because it's easier to deal with and you want it to grow dynamically. But as you noticed, there's no guarantee of compatibility of its storage with a Vec<u8>, and no safe conversion.



Why not take the problem the other way and build a convenient facade for a Vec<u8> ?



type Rgb = [u8; 3];

#[derive(Debug)]
struct Img(Vec<u8>);

impl Img
fn new() -> Img
Img(Vec::new())


fn push(&mut self, rgb: &Rgb)
self.0.push(rgb[0]);
self.0.push(rgb[1]);
self.0.push(rgb[2]);


// other convenient methods


fn main()
let mut img = Img::new();
let rgb : Rgb = [1, 2, 3];
img.push(&rgb);
img.push(&rgb);
println!(":?", img);






share|improve this answer






















  • For what it's worth, the image library basically provides such a façade in the form of the ImageBuffer struct, so the right answer is probably to simply use that.
    – Sven Marnach
    Nov 9 at 10:20










  • I didn't use ImageBuffer because it has a fixed width & height and as I noted in the question I want to grow by Vec<> dynamically.
    – Timmmm
    Nov 9 at 11:13














up vote
2
down vote













You choose the Vec<Rgb<u8>> storage format because it's easier to deal with and you want it to grow dynamically. But as you noticed, there's no guarantee of compatibility of its storage with a Vec<u8>, and no safe conversion.



Why not take the problem the other way and build a convenient facade for a Vec<u8> ?



type Rgb = [u8; 3];

#[derive(Debug)]
struct Img(Vec<u8>);

impl Img
fn new() -> Img
Img(Vec::new())


fn push(&mut self, rgb: &Rgb)
self.0.push(rgb[0]);
self.0.push(rgb[1]);
self.0.push(rgb[2]);


// other convenient methods


fn main()
let mut img = Img::new();
let rgb : Rgb = [1, 2, 3];
img.push(&rgb);
img.push(&rgb);
println!(":?", img);






share|improve this answer






















  • For what it's worth, the image library basically provides such a façade in the form of the ImageBuffer struct, so the right answer is probably to simply use that.
    – Sven Marnach
    Nov 9 at 10:20










  • I didn't use ImageBuffer because it has a fixed width & height and as I noted in the question I want to grow by Vec<> dynamically.
    – Timmmm
    Nov 9 at 11:13












up vote
2
down vote










up vote
2
down vote









You choose the Vec<Rgb<u8>> storage format because it's easier to deal with and you want it to grow dynamically. But as you noticed, there's no guarantee of compatibility of its storage with a Vec<u8>, and no safe conversion.



Why not take the problem the other way and build a convenient facade for a Vec<u8> ?



type Rgb = [u8; 3];

#[derive(Debug)]
struct Img(Vec<u8>);

impl Img
fn new() -> Img
Img(Vec::new())


fn push(&mut self, rgb: &Rgb)
self.0.push(rgb[0]);
self.0.push(rgb[1]);
self.0.push(rgb[2]);


// other convenient methods


fn main()
let mut img = Img::new();
let rgb : Rgb = [1, 2, 3];
img.push(&rgb);
img.push(&rgb);
println!(":?", img);






share|improve this answer














You choose the Vec<Rgb<u8>> storage format because it's easier to deal with and you want it to grow dynamically. But as you noticed, there's no guarantee of compatibility of its storage with a Vec<u8>, and no safe conversion.



Why not take the problem the other way and build a convenient facade for a Vec<u8> ?



type Rgb = [u8; 3];

#[derive(Debug)]
struct Img(Vec<u8>);

impl Img
fn new() -> Img
Img(Vec::new())


fn push(&mut self, rgb: &Rgb)
self.0.push(rgb[0]);
self.0.push(rgb[1]);
self.0.push(rgb[2]);


// other convenient methods


fn main()
let mut img = Img::new();
let rgb : Rgb = [1, 2, 3];
img.push(&rgb);
img.push(&rgb);
println!(":?", img);







share|improve this answer














share|improve this answer



share|improve this answer








edited Nov 8 at 20:14

























answered Nov 8 at 19:37









Denys Séguret

270k51568585




270k51568585











  • For what it's worth, the image library basically provides such a façade in the form of the ImageBuffer struct, so the right answer is probably to simply use that.
    – Sven Marnach
    Nov 9 at 10:20










  • I didn't use ImageBuffer because it has a fixed width & height and as I noted in the question I want to grow by Vec<> dynamically.
    – Timmmm
    Nov 9 at 11:13
















  • For what it's worth, the image library basically provides such a façade in the form of the ImageBuffer struct, so the right answer is probably to simply use that.
    – Sven Marnach
    Nov 9 at 10:20










  • I didn't use ImageBuffer because it has a fixed width & height and as I noted in the question I want to grow by Vec<> dynamically.
    – Timmmm
    Nov 9 at 11:13















For what it's worth, the image library basically provides such a façade in the form of the ImageBuffer struct, so the right answer is probably to simply use that.
– Sven Marnach
Nov 9 at 10:20




For what it's worth, the image library basically provides such a façade in the form of the ImageBuffer struct, so the right answer is probably to simply use that.
– Sven Marnach
Nov 9 at 10:20












I didn't use ImageBuffer because it has a fixed width & height and as I noted in the question I want to grow by Vec<> dynamically.
– Timmmm
Nov 9 at 11:13




I didn't use ImageBuffer because it has a fixed width & height and as I noted in the question I want to grow by Vec<> dynamically.
– Timmmm
Nov 9 at 11:13

















 

draft saved


draft discarded















































 


draft saved


draft discarded














StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53213025%2fhow-to-convert-vecrgbu8-to-vecu8%23new-answer', 'question_page');

);

Post as a guest














































































Popular posts from this blog

Use pre created SQLite database for Android project in kotlin

Darth Vader #20

Ondo