4 ms·
I wouldn't call that code idiomatic either: it is cleaned up from the automatic translation, but it still a far cry from what Rust written by hand would look li
by estebank 5y ago
I wouldn't call that code idiomatic either: it is cleaned up from the automatic translation, but it still a far cry from what Rust written by hand would look like
pub static mut g_color_table: [crate::src::qcommon::q_shared::vec4_t; 8] = [
[0f32, 0f32, 0f32, 1f32],
[1f32, 0f32, 0f32, 1f32],
[0f32, 1f32, 0f32, 1f32],
[1f32, 1f32, 0f32, 1f32],
[0f32, 0f32, 1f32, 1f32],
[0f32, 1f32, 1f32, 1f32],
[1f32, 0f32, 1f32, 1f32],
[1f32, 1f32, 1f32, 1f32],
];
would maybe look like
pub static mut g_color_table: [[f32; 4]; 8] = [
[0, 0, 0, 1],
[1, 0, 0, 1],
[0, 1, 0, 1],
[1, 1, 0, 1],
[0, 0, 1, 1],
[0, 1, 1, 1],
[1, 0, 1, 1],
[1, 1, 1, 1],
];
but it still looks weird to me (a static mut would be uncommon in a design, and not having a new-type to represent these would also be uncommon).
If you are interested in looking what Rust written from the ground up in the same domain looks like, you can maybe look at Bevy[1].
The biggest source of "noise" in Rust is explicit type conversions, FP constructs and longer types (`.into()`/`.as_mut_ref()`/`.map()`/`Result<Option<T>, E>`).
[1]: https://github.com/bevyengine/bevy/blob/main/crates/bevy_render/src/mesh/mesh.rs https://github.com/bevyengine/bevy/blob/main/crates/bevy_ren...
- johnisgood 5y agoBufferInfo { buffer_usage: BufferUsage::VERTEX, ..Default::default() }, What is "..Default" here?
- estebank 5y ago`Default` is a trait[1] that can be implemented on any type that can be conceived to have a default value. For example, Option has something like: impl<T> Default for Option<T> { fn default() -> Option<T> { None } } If every field of a struct impl Default, then you can you can use the `#[derive(Default)]` annotation to auto-fill that impl for that struct, otherwise you have to write it by hand. The .. is the spread operator, and it takes every field of the value on the right and applies it to every field of the struct constructor on the left. This only works for the same type (it's not only looking at the field names). `Default::default()` is a qualified call on the trait equivalent to `<_ as Default>::default()`, where `_` is inferred from context to be `BufferInfo`. What that code is doing is saying "build a default BufferInfo with field buffer_usage set to VERTEX". The spread operator has a limitation you might have intuited from the description that it can't work for types where some field(s) should always be set but not others. To get around that you can use the builder pattern BufferInfo::with_buffer_usage(BufferUsage::VERTEX).build() and there's a pre-RFC in flight to become an RFC to add support for struct Foo { field: i32 = 42, } let foo = Foo { .. }; [1]: https://doc.rust-lang.org/std/default/trait.Default.html https://doc.rust-lang.org/std/default/trait.Default.html
- deleted 5y ago[deleted]
- ufmace 5y agoNormally in Rust, to initialize a struct, you must specify a value for every field of it, since null and uninitialized values aren't allowed. To make it a little more convenient, there's a trait called Default which can be implemented for your struct to provide an instance with every field set to a value that you think should be the default. And the .. syntax allows you to copy values for the rest of the fields of a struct from another struct instance. So calling that with Default::default() gets an instance with the default values and uses those values to fill all of the rest of the fields of the struct. Thus if you have a big struct where most values are the default most of the time, you can create instances of it with one or two fields set to something different like this without an extra few dozen lines of repetitive boilerplate for every other field of the struct.
- tialaramex 5y agoSo, what we're saying here is in effect, "and all the other fields should have their default value". Specifically, when you initialise a structure like this, the .. is "struct update syntax" and is followed by an instance of that structure from which remaining fields will be copied. Default is a Rust trait (similar to an interface if you've never seen Rust traits before) and it has the method default() which gives you a default of whatever type. Rust has type inference, if you don't specify a type, but there is only one possibility that could work, the type inference might (and in this case does) see that and you needn't bother laboriously writing down the type. This can only happen where there was no possible ambiguity. In this case, the only type you can use for struct update syntax is the structure type you're updating of course, BufferInfo, and so Default::default() must mean the default BufferInfo. If you found the definition of BufferInfo it probably says #[derive(Default)] which means, using a macro just implement Default for this structure in the obvious way, although it might actually have an explicit Default written out instead.