+/* 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 type *type, int embedded_offset,
+ CORE_ADDR address, struct ui_file *stream,
+ int recurse, struct value *val,
+ const struct value_print_options *options)
+{
+ int i;
+ int first_field;
+
+ if (rust_slice_type_p (type) && strcmp (TYPE_NAME (type), "&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) + embedded_offset);
+ 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 (type) != NULL)
+ fprintf_filtered (stream, "%s", TYPE_NAME (type));
+
+ if (TYPE_NFIELDS (type) == 0)
+ return;
+
+ if (TYPE_NAME (type) != 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_NFIELDS (type); ++i)
+ {
+ if (field_is_static (&TYPE_FIELD (type, 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_filtered (TYPE_FIELD_NAME (type, i), stream);
+ fputs_filtered (": ", stream);
+ }
+
+ val_print (TYPE_FIELD_TYPE (type, i),
+ embedded_offset + TYPE_FIELD_BITPOS (type, i) / 8,
+ address,
+ stream, recurse + 1, val, &opts,
+ current_language);
+ }
+
+ 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 type *type, int embedded_offset,
+ CORE_ADDR address, struct ui_file *stream,
+ int recurse, struct value *val,
+ const struct value_print_options *options)
+{
+ struct value_print_options opts = *options;
+
+ opts.deref_ref = 0;
+
+ 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 (type),
+ metadata_style.style ().ptr (), nullptr);
+ return;
+ }
+
+ const gdb_byte *valaddr = value_contents_for_printing (val);
+ struct field *variant_field = rust_enum_variant (type, valaddr);
+ embedded_offset += FIELD_BITPOS (*variant_field) / 8;
+ struct type *variant_type = FIELD_TYPE (*variant_field);
+
+ int nfields = TYPE_NFIELDS (variant_type);
+
+ bool is_tuple = rust_tuple_struct_type_p (variant_type);
+
+ fprintf_filtered (stream, "%s", TYPE_NAME (variant_type));
+ 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 < TYPE_NFIELDS (variant_type); j++)
+ {
+ if (!first_field)
+ fputs_filtered (", ", stream);
+ first_field = false;
+
+ if (!is_tuple)
+ fprintf_filtered (stream, "%s: ",
+ TYPE_FIELD_NAME (variant_type, j));
+
+ val_print (TYPE_FIELD_TYPE (variant_type, j),
+ (embedded_offset
+ + TYPE_FIELD_BITPOS (variant_type, j) / 8),
+ address,
+ stream, recurse + 1, val, &opts,
+ current_language);
+ }
+
+ if (is_tuple)
+ fputs_filtered (")", stream);
+ else
+ fputs_filtered ("}", stream);
+}
+