@@ -236,3 +236,88 @@ pub(crate) fn element_godot_type_name<T: ArrayElement>() -> String {
236236// pub(crate) fn element_godot_type_name<T: ArrayElement>() -> String {
237237// <T::Via as GodotType>::godot_type_name()
238238// }
239+
240+ // ----------------------------------------------------------------------------------------------------------------------------------------------
241+
242+ /// Implemented for types that can be used as immutable default parameters in `#[func]` methods.
243+ ///
244+ /// This trait ensures that default parameter values cannot be mutated by callers, preventing the Python "mutable default argument" problem
245+ /// where a single default value is shared across multiple calls.
246+ ///
247+ /// Post-processes the default value in some cases, e.g. makes `Array<T>` read-only via `into_read_only()`.
248+ ///
249+ /// At the moment, this trait is conservatively implemented for types where immutability can be statically guaranteed.
250+ /// Depending on usage, the API might be expanded in the future to allow defaults whose immutability is only determined
251+ /// at runtime (e.g. untyped arrays/dictionaries where all element types are immutable).
252+ ///
253+ /// # Safety
254+ /// Allows to use the implementors in a limited `Sync` context. Implementing this trait asserts that `Self` is either:
255+ /// - `Copy`, i.e. each instance is truly independent.
256+ /// - Thread-safe in the sense that `clone()` is thread-safe. Individual clones must not offer a way to mutate the value or cause race conditions.
257+ #[ diagnostic:: on_unimplemented(
258+ message = "#[opt(default = ...)] only supports a set of truly immutable types" ,
259+ label = "this type is not immutable and thus not eligible for a default value"
260+ ) ]
261+ pub unsafe trait GodotImmutable : GodotConvert + Sized {
262+ fn into_runtime_immutable ( self ) -> Self {
263+ self
264+ }
265+ }
266+
267+ mod godot_immutable_impls {
268+ use super :: GodotImmutable ;
269+ use crate :: builtin:: * ;
270+ use crate :: meta:: ArrayElement ;
271+
272+ unsafe impl GodotImmutable for bool { }
273+ unsafe impl GodotImmutable for i8 { }
274+ unsafe impl GodotImmutable for u8 { }
275+ unsafe impl GodotImmutable for i16 { }
276+ unsafe impl GodotImmutable for u16 { }
277+ unsafe impl GodotImmutable for i32 { }
278+ unsafe impl GodotImmutable for u32 { }
279+ unsafe impl GodotImmutable for i64 { }
280+ unsafe impl GodotImmutable for f32 { }
281+ unsafe impl GodotImmutable for f64 { }
282+
283+ // No NodePath, Callable, Signal, Rid, Variant.
284+ unsafe impl GodotImmutable for Aabb { }
285+ unsafe impl GodotImmutable for Basis { }
286+ unsafe impl GodotImmutable for Color { }
287+ unsafe impl GodotImmutable for GString { }
288+ unsafe impl GodotImmutable for Plane { }
289+ unsafe impl GodotImmutable for Projection { }
290+ unsafe impl GodotImmutable for Quaternion { }
291+ unsafe impl GodotImmutable for Rect2 { }
292+ unsafe impl GodotImmutable for Rect2i { }
293+ unsafe impl GodotImmutable for StringName { }
294+ unsafe impl GodotImmutable for Transform2D { }
295+ unsafe impl GodotImmutable for Transform3D { }
296+ unsafe impl GodotImmutable for Vector2 { }
297+ unsafe impl GodotImmutable for Vector2i { }
298+ unsafe impl GodotImmutable for Vector3 { }
299+ unsafe impl GodotImmutable for Vector3i { }
300+ unsafe impl GodotImmutable for Vector4 { }
301+ unsafe impl GodotImmutable for Vector4i { }
302+
303+ unsafe impl GodotImmutable for PackedByteArray { }
304+ unsafe impl GodotImmutable for PackedColorArray { }
305+ unsafe impl GodotImmutable for PackedFloat32Array { }
306+ unsafe impl GodotImmutable for PackedFloat64Array { }
307+ unsafe impl GodotImmutable for PackedInt32Array { }
308+ unsafe impl GodotImmutable for PackedInt64Array { }
309+ unsafe impl GodotImmutable for PackedStringArray { }
310+ unsafe impl GodotImmutable for PackedVector2Array { }
311+ unsafe impl GodotImmutable for PackedVector3Array { }
312+ #[ cfg( since_api = "4.3" ) ]
313+ unsafe impl GodotImmutable for PackedVector4Array { }
314+
315+ unsafe impl < T > GodotImmutable for Array < T >
316+ where
317+ T : GodotImmutable + ArrayElement ,
318+ {
319+ fn into_runtime_immutable ( self ) -> Self {
320+ self . into_read_only ( )
321+ }
322+ }
323+ }
0 commit comments