+static void rust_value_print_inner (struct value *val, struct ui_file *stream,
+ int recurse,
+ const struct value_print_options *options);
+
+/* Helper function to print a string slice. */
+
+static void
+rust_val_print_str (struct ui_file *stream, struct value *val,
+ const struct value_print_options *options)
+{
+ struct value *base = value_struct_elt (&val, NULL, "data_ptr", NULL,
+ "slice");
+ struct value *len = value_struct_elt (&val, NULL, "length", NULL, "slice");
+
+ val_print_string (TYPE_TARGET_TYPE (value_type (base)), "UTF-8",
+ value_as_address (base), value_as_long (len), stream,
+ options);
+}
+
+/* rust_val_print helper for structs and untagged unions. */
+
+static void
+val_print_struct (struct value *val, struct ui_file *stream, int recurse,
+ const struct value_print_options *options)
+{
+ int i;
+ int first_field;
+ struct type *type = check_typedef (value_type (val));
+
+ if (rust_slice_type_p (type) && strcmp (type->name (), "&str") == 0)
+ {
+ /* If what we are printing here is actually a string within a
+ structure then VAL will be the original parent value, while TYPE
+ will be the type of the structure representing the string we want
+ to print.
+ However, RUST_VAL_PRINT_STR looks up the fields of the string
+ inside VAL, assuming that VAL is the string.
+ So, recreate VAL as a value representing just the string. */
+ val = value_at_lazy (type, value_address (val));
+ rust_val_print_str (stream, val, options);
+ return;
+ }
+
+ bool is_tuple = rust_tuple_type_p (type);
+ bool is_tuple_struct = !is_tuple && rust_tuple_struct_type_p (type);
+ struct value_print_options opts;
+
+ if (!is_tuple)
+ {
+ if (type->name () != NULL)
+ fprintf_filtered (stream, "%s", type->name ());
+
+ if (type->num_fields () == 0)
+ return;
+
+ if (type->name () != NULL)
+ fputs_filtered (" ", stream);
+ }
+
+ if (is_tuple || is_tuple_struct)
+ fputs_filtered ("(", stream);
+ else
+ fputs_filtered ("{", stream);
+
+ opts = *options;
+ opts.deref_ref = 0;
+
+ first_field = 1;
+ for (i = 0; i < type->num_fields (); ++i)
+ {
+ if (field_is_static (&type->field (i)))
+ continue;
+
+ if (!first_field)
+ fputs_filtered (",", stream);
+
+ if (options->prettyformat)
+ {
+ fputs_filtered ("\n", stream);
+ print_spaces_filtered (2 + 2 * recurse, stream);
+ }
+ else if (!first_field)
+ fputs_filtered (" ", stream);
+
+ first_field = 0;
+
+ if (!is_tuple && !is_tuple_struct)
+ {
+ fputs_styled (TYPE_FIELD_NAME (type, i),
+ variable_name_style.style (), stream);
+ fputs_filtered (": ", stream);
+ }
+
+ rust_value_print_inner (value_field (val, i), stream, recurse + 1,
+ &opts);
+ }
+
+ if (options->prettyformat)
+ {
+ fputs_filtered ("\n", stream);
+ print_spaces_filtered (2 * recurse, stream);
+ }
+
+ if (is_tuple || is_tuple_struct)
+ fputs_filtered (")", stream);
+ else
+ fputs_filtered ("}", stream);
+}
+
+/* rust_val_print helper for discriminated unions (Rust enums). */
+
+static void
+rust_print_enum (struct value *val, struct ui_file *stream, int recurse,
+ const struct value_print_options *options)
+{
+ struct value_print_options opts = *options;
+ struct type *type = check_typedef (value_type (val));
+
+ opts.deref_ref = 0;
+
+ gdb_assert (rust_enum_p (type));
+ gdb::array_view<const gdb_byte> view (value_contents_for_printing (val),
+ TYPE_LENGTH (value_type (val)));
+ type = resolve_dynamic_type (type, view, value_address (val));
+
+ if (rust_empty_enum_p (type))
+ {
+ /* Print the enum type name here to be more clear. */
+ fprintf_filtered (stream, _("%s {%p[<No data fields>%p]}"),
+ type->name (),
+ metadata_style.style ().ptr (), nullptr);
+ return;
+ }
+
+ int variant_fieldno = rust_enum_variant (type);
+ val = value_field (val, variant_fieldno);
+ struct type *variant_type = TYPE_FIELD_TYPE (type, variant_fieldno);
+
+ int nfields = variant_type->num_fields ();
+
+ bool is_tuple = rust_tuple_struct_type_p (variant_type);
+
+ fprintf_filtered (stream, "%s", variant_type->name ());
+ if (nfields == 0)
+ {
+ /* In case of a nullary variant like 'None', just output
+ the name. */
+ return;
+ }
+
+ /* In case of a non-nullary variant, we output 'Foo(x,y,z)'. */
+ if (is_tuple)
+ fprintf_filtered (stream, "(");
+ else
+ {
+ /* struct variant. */
+ fprintf_filtered (stream, "{");
+ }
+
+ bool first_field = true;
+ for (int j = 0; j < variant_type->num_fields (); j++)
+ {
+ if (!first_field)
+ fputs_filtered (", ", stream);
+ first_field = false;
+
+ if (!is_tuple)
+ fprintf_filtered (stream, "%ps: ",
+ styled_string (variable_name_style.style (),
+ TYPE_FIELD_NAME (variant_type, j)));
+
+ rust_value_print_inner (value_field (val, j), stream, recurse + 1,
+ &opts);
+ }
+
+ if (is_tuple)
+ fputs_filtered (")", stream);
+ else
+ fputs_filtered ("}", stream);
+}
+