Skip to main content

Save

Struct Save 

Source
pub struct Save {
    pub character: Character,
    pub quests: Quests,
    pub waypoints: Waypoints,
    pub npcs: Placeholder,
    pub attributes: Attributes,
    pub skills: SkillPoints,
    pub items: Placeholder,
    /* private fields */
}
Expand description

Full in-memory save model.

Unknown payloads for unmodeled sections are preserved in placeholder structs. Invariants:

  • format() and version() are synchronized through set_format.
  • expansion_type() is canonical and must be changed through set_expansion_type.
  • Character/attribute level must be changed through set_level.

Fields§

§character: Character

Character section.

§quests: Quests

Quests section.

§waypoints: Waypoints

Waypoints section.

§npcs: Placeholder

NPC section (placeholder model).

§attributes: Attributes

Attributes section.

§skills: SkillPoints

Skills section.

§items: Placeholder

Items section (placeholder model).

Implementations§

Source§

impl Save

Source

pub fn new(format: FormatId, class: Class) -> Save

Build a new blank save for a target format/class.

V99 defaults to Expansion; V105 and unknown formats default to RotW. Call set_expansion_type afterward if you need Classic.

Source

pub fn format(&self) -> FormatId

Examples found in repository?
examples/inspect_issues.rs (line 11)
3fn main() -> Result<(), Box<dyn std::error::Error>> {
4    // Start from a known good file.
5    let bytes = std::fs::read("assets/test/Joe.d2s")?;
6
7    // Strict mode fails fast on invalid data.
8    let strict = Save::parse(&bytes, Strictness::Strict)?;
9    println!(
10        "Strict parse OK: format={:?}, name={}",
11        strict.save.format(),
12        strict.save.character.name
13    );
14
15    // Validation is separate from parsing, so check the save on its own.
16    let validation = strict.save.validate();
17    println!("\nValidation issues: {}", validation.issues.len());
18    for (index, issue) in validation.issues.iter().enumerate() {
19        println!("#{index} [{:?}] {}", issue.code, issue.message);
20    }
21
22    // Break the payload on purpose so we can inspect non-fatal issues.
23    // - byte 0 breaks signature
24    // - truncation simulates a damaged or incomplete file
25    let mut damaged = bytes.clone();
26    damaged[0] = 0x00;
27    damaged.truncate(220);
28
29    // Lax mode keeps going and collects issues.
30    let lax = Save::parse(&damaged, Strictness::Lax)?;
31    println!("\nLax parse issues: {}", lax.issues.len());
32    for (index, issue) in lax.issues.iter().enumerate() {
33        println!(
34            "#{index} [{:?}/{:?}] section={:?} offset={:?} expected={:?} found={:?}\n  {}",
35            issue.severity,
36            issue.kind,
37            issue.section,
38            issue.offset,
39            issue.expected,
40            issue.found,
41            issue.message
42        );
43    }
44
45    // Strict mode should reject the damaged payload.
46    match Save::parse(&damaged, Strictness::Strict) {
47        Ok(_) => println!("\nUnexpected: strict parse accepted damaged payload."),
48        Err(error) => println!("\nStrict parse error: {error}"),
49    }
50
51    Ok(())
52}
More examples
Hide additional examples
examples/edit_character.rs (line 17)
4fn main() -> Result<(), Box<dyn std::error::Error>> {
5    let input_path = "assets/test/Warlock_v105.d2s";
6    let output_name = "WarlockDemo";
7    let output_dir = "target/example-output";
8    let output_path = format!("{output_dir}/{output_name}.d2s");
9
10    let bytes = std::fs::read(input_path)?;
11    let parsed = Save::parse(&bytes, Strictness::Strict)?;
12    if !parsed.issues.is_empty() {
13        return Err(format!("fixture parsed with issues: {:?}", parsed.issues).into());
14    }
15
16    let mut save = parsed.save;
17    let target_format = save.format();
18
19    println!(
20        "Loaded {:?} / {} / lvl {}",
21        target_format,
22        save.character.name,
23        save.character.level()
24    );
25
26    // Keep the file name and in-game name aligned.
27    save.character.name = output_name.to_string();
28
29    // Keep character.level and attributes.level in sync.
30    save.set_level(75);
31
32    // Main stats.
33    save.attributes.strength.value = 220;
34    save.attributes.dexterity.value = 175;
35    save.attributes.vitality.value = 260;
36    save.attributes.energy.value = 110;
37    save.attributes.statpts.value = 25;
38    save.attributes.newskills.value = 10;
39    save.attributes.gold.value = 200_000;
40    save.attributes.goldbank.value = 2_500_000;
41
42    // These stats are fixed-point in the save file (Q8), so the helpers take in-game values.
43    save.attributes.set_max_hp(2200);
44    save.attributes.set_hp(2200);
45    save.attributes.set_max_mana(900);
46    save.attributes.set_mana(900);
47    save.attributes.set_max_stamina(1200);
48    save.attributes.set_stamina(1200);
49
50    // Use the D2R name lookup when it exists.
51    // Fall back to raw slot indexes when it does not.
52    if save.skills.set_by_name_d2r(save.character.class, "Bash", 20).is_err() {
53        save.skills.set(0, 20);
54    }
55    if save.skills.set_by_name_d2r(save.character.class, "Battle Orders", 20).is_err() {
56        save.skills.set(23, 20);
57    }
58    if save.skills.set_by_name_d2r(save.character.class, "Whirlwind", 20).is_err() {
59        save.skills.set(25, 20);
60    }
61
62    // Give Act I all waypoints.
63    save.waypoints.normal.act1.set_all(true);
64
65    // Edit one quest state.
66    save.quests.normal.act1.q1.state.insert(QuestFlag::Started);
67
68    let act1_catacombs = save.waypoints.normal.act1.get_by_index(8)?;
69    let quest_started = save.quests.normal.act1.q1.state.contains(&QuestFlag::Started);
70
71    // Write back to the same detected format.
72    let output_bytes = save.encode_for(target_format, CompatibilityChecks::Enforce)?;
73    std::fs::create_dir_all(output_dir)?;
74    std::fs::write(&output_path, output_bytes)?;
75
76    println!("Wrote {output_path}");
77    println!("Now: {} / lvl {}", save.character.name, save.character.level());
78    println!(
79        "Stats: str={} dex={} vit={} ene={}",
80        save.attributes.strength.value,
81        save.attributes.dexterity.value,
82        save.attributes.vitality.value,
83        save.attributes.energy.value
84    );
85    println!(
86        "Resources: hp={} mana={} stamina={}",
87        save.attributes.get_max_hp(),
88        save.attributes.get_max_mana(),
89        save.attributes.get_max_stamina()
90    );
91    println!("Act I / Catacombs waypoint: {act1_catacombs}");
92    println!("Quest q1 started: {quest_started}");
93
94    Ok(())
95}
Source

pub fn version(&self) -> u32

Header version synchronized with the save format.

Source

pub fn set_format(&mut self, format: FormatId)

Set output format and synchronize the numeric version field.

Source

pub fn game_edition(&self) -> Option<GameEdition>

Source

pub fn set_level(&mut self, level: u8)

Set both character level fields kept in separate sections.

Examples found in repository?
examples/edit_character.rs (line 30)
4fn main() -> Result<(), Box<dyn std::error::Error>> {
5    let input_path = "assets/test/Warlock_v105.d2s";
6    let output_name = "WarlockDemo";
7    let output_dir = "target/example-output";
8    let output_path = format!("{output_dir}/{output_name}.d2s");
9
10    let bytes = std::fs::read(input_path)?;
11    let parsed = Save::parse(&bytes, Strictness::Strict)?;
12    if !parsed.issues.is_empty() {
13        return Err(format!("fixture parsed with issues: {:?}", parsed.issues).into());
14    }
15
16    let mut save = parsed.save;
17    let target_format = save.format();
18
19    println!(
20        "Loaded {:?} / {} / lvl {}",
21        target_format,
22        save.character.name,
23        save.character.level()
24    );
25
26    // Keep the file name and in-game name aligned.
27    save.character.name = output_name.to_string();
28
29    // Keep character.level and attributes.level in sync.
30    save.set_level(75);
31
32    // Main stats.
33    save.attributes.strength.value = 220;
34    save.attributes.dexterity.value = 175;
35    save.attributes.vitality.value = 260;
36    save.attributes.energy.value = 110;
37    save.attributes.statpts.value = 25;
38    save.attributes.newskills.value = 10;
39    save.attributes.gold.value = 200_000;
40    save.attributes.goldbank.value = 2_500_000;
41
42    // These stats are fixed-point in the save file (Q8), so the helpers take in-game values.
43    save.attributes.set_max_hp(2200);
44    save.attributes.set_hp(2200);
45    save.attributes.set_max_mana(900);
46    save.attributes.set_mana(900);
47    save.attributes.set_max_stamina(1200);
48    save.attributes.set_stamina(1200);
49
50    // Use the D2R name lookup when it exists.
51    // Fall back to raw slot indexes when it does not.
52    if save.skills.set_by_name_d2r(save.character.class, "Bash", 20).is_err() {
53        save.skills.set(0, 20);
54    }
55    if save.skills.set_by_name_d2r(save.character.class, "Battle Orders", 20).is_err() {
56        save.skills.set(23, 20);
57    }
58    if save.skills.set_by_name_d2r(save.character.class, "Whirlwind", 20).is_err() {
59        save.skills.set(25, 20);
60    }
61
62    // Give Act I all waypoints.
63    save.waypoints.normal.act1.set_all(true);
64
65    // Edit one quest state.
66    save.quests.normal.act1.q1.state.insert(QuestFlag::Started);
67
68    let act1_catacombs = save.waypoints.normal.act1.get_by_index(8)?;
69    let quest_started = save.quests.normal.act1.q1.state.contains(&QuestFlag::Started);
70
71    // Write back to the same detected format.
72    let output_bytes = save.encode_for(target_format, CompatibilityChecks::Enforce)?;
73    std::fs::create_dir_all(output_dir)?;
74    std::fs::write(&output_path, output_bytes)?;
75
76    println!("Wrote {output_path}");
77    println!("Now: {} / lvl {}", save.character.name, save.character.level());
78    println!(
79        "Stats: str={} dex={} vit={} ene={}",
80        save.attributes.strength.value,
81        save.attributes.dexterity.value,
82        save.attributes.vitality.value,
83        save.attributes.energy.value
84    );
85    println!(
86        "Resources: hp={} mana={} stamina={}",
87        save.attributes.get_max_hp(),
88        save.attributes.get_max_mana(),
89        save.attributes.get_max_stamina()
90    );
91    println!("Act I / Catacombs waypoint: {act1_catacombs}");
92    println!("Quest q1 started: {quest_started}");
93
94    Ok(())
95}
Source

pub fn expansion_type(&self) -> ExpansionType

Source

pub fn set_expansion_type(&mut self, expansion_type: ExpansionType)

Source

pub fn parse( byte_slice: &[u8], strictness: Strictness, ) -> Result<ParsedSave, ParseHardError>

Parse a save with explicit strictness.

Examples found in repository?
examples/inspect_issues.rs (line 8)
3fn main() -> Result<(), Box<dyn std::error::Error>> {
4    // Start from a known good file.
5    let bytes = std::fs::read("assets/test/Joe.d2s")?;
6
7    // Strict mode fails fast on invalid data.
8    let strict = Save::parse(&bytes, Strictness::Strict)?;
9    println!(
10        "Strict parse OK: format={:?}, name={}",
11        strict.save.format(),
12        strict.save.character.name
13    );
14
15    // Validation is separate from parsing, so check the save on its own.
16    let validation = strict.save.validate();
17    println!("\nValidation issues: {}", validation.issues.len());
18    for (index, issue) in validation.issues.iter().enumerate() {
19        println!("#{index} [{:?}] {}", issue.code, issue.message);
20    }
21
22    // Break the payload on purpose so we can inspect non-fatal issues.
23    // - byte 0 breaks signature
24    // - truncation simulates a damaged or incomplete file
25    let mut damaged = bytes.clone();
26    damaged[0] = 0x00;
27    damaged.truncate(220);
28
29    // Lax mode keeps going and collects issues.
30    let lax = Save::parse(&damaged, Strictness::Lax)?;
31    println!("\nLax parse issues: {}", lax.issues.len());
32    for (index, issue) in lax.issues.iter().enumerate() {
33        println!(
34            "#{index} [{:?}/{:?}] section={:?} offset={:?} expected={:?} found={:?}\n  {}",
35            issue.severity,
36            issue.kind,
37            issue.section,
38            issue.offset,
39            issue.expected,
40            issue.found,
41            issue.message
42        );
43    }
44
45    // Strict mode should reject the damaged payload.
46    match Save::parse(&damaged, Strictness::Strict) {
47        Ok(_) => println!("\nUnexpected: strict parse accepted damaged payload."),
48        Err(error) => println!("\nStrict parse error: {error}"),
49    }
50
51    Ok(())
52}
More examples
Hide additional examples
examples/waypoints.rs (line 6)
4fn main() -> Result<(), Box<dyn std::error::Error>> {
5    let bytes = std::fs::read("assets/test/Joe.d2s")?;
6    let parsed = Save::parse(&bytes, Strictness::Strict)?;
7    let mut save = parsed.save;
8
9    // Read by index.
10    let catacombs_was_unlocked = save.waypoints.hell.act1.get_by_index(8)?;
11    println!("Hell Act I / Catacombs unlocked: {catacombs_was_unlocked}");
12
13    // Set by waypoint id.
14    save.waypoints.hell.act1.set(Waypoint::Catacombs, true)?;
15    let catacombs_is_unlocked = save.waypoints.hell.act1.get(Waypoint::Catacombs)?;
16    println!("Hell Act I / Catacombs now unlocked: {catacombs_is_unlocked}");
17
18    // Set by index.
19    save.waypoints.normal.act4.set_by_index(2, true)?;
20    println!(
21        "Normal Act IV / River of Flames unlocked: {}",
22        save.waypoints.normal.act4.get_by_index(2)?
23    );
24
25    // Bulk update one difficulty.
26    save.waypoints.nightmare.set_all(true);
27    println!(
28        "Nightmare Act II / Sewers unlocked after set_all: {}",
29        save.waypoints.nightmare.act2.get_by_index(1)?
30    );
31
32    // Wrong-act usage returns an explicit error.
33    match save.waypoints.normal.act1.set(Waypoint::LutGholein, true) {
34        Err(WaypointError::WrongAct { waypoint, expected, actual }) => {
35            println!("WrongAct: {waypoint:?} belongs to {actual:?}, expected {expected:?}.")
36        }
37        Ok(_) => println!("Unexpected: wrong-act set was accepted."),
38        Err(error) => println!("Unexpected waypoint error: {error}"),
39    }
40
41    // Out-of-range reads return an explicit error.
42    match save.waypoints.normal.act4.get_by_index(3) {
43        Err(WaypointError::IndexOutOfRange { act, index, max_index }) => {
44            println!("IndexOutOfRange: {act:?} index {index} (max {max_index}).")
45        }
46        Ok(_) => println!("Unexpected: out-of-range read was accepted."),
47        Err(error) => println!("Unexpected waypoint error: {error}"),
48    }
49
50    Ok(())
51}
examples/edit_character.rs (line 11)
4fn main() -> Result<(), Box<dyn std::error::Error>> {
5    let input_path = "assets/test/Warlock_v105.d2s";
6    let output_name = "WarlockDemo";
7    let output_dir = "target/example-output";
8    let output_path = format!("{output_dir}/{output_name}.d2s");
9
10    let bytes = std::fs::read(input_path)?;
11    let parsed = Save::parse(&bytes, Strictness::Strict)?;
12    if !parsed.issues.is_empty() {
13        return Err(format!("fixture parsed with issues: {:?}", parsed.issues).into());
14    }
15
16    let mut save = parsed.save;
17    let target_format = save.format();
18
19    println!(
20        "Loaded {:?} / {} / lvl {}",
21        target_format,
22        save.character.name,
23        save.character.level()
24    );
25
26    // Keep the file name and in-game name aligned.
27    save.character.name = output_name.to_string();
28
29    // Keep character.level and attributes.level in sync.
30    save.set_level(75);
31
32    // Main stats.
33    save.attributes.strength.value = 220;
34    save.attributes.dexterity.value = 175;
35    save.attributes.vitality.value = 260;
36    save.attributes.energy.value = 110;
37    save.attributes.statpts.value = 25;
38    save.attributes.newskills.value = 10;
39    save.attributes.gold.value = 200_000;
40    save.attributes.goldbank.value = 2_500_000;
41
42    // These stats are fixed-point in the save file (Q8), so the helpers take in-game values.
43    save.attributes.set_max_hp(2200);
44    save.attributes.set_hp(2200);
45    save.attributes.set_max_mana(900);
46    save.attributes.set_mana(900);
47    save.attributes.set_max_stamina(1200);
48    save.attributes.set_stamina(1200);
49
50    // Use the D2R name lookup when it exists.
51    // Fall back to raw slot indexes when it does not.
52    if save.skills.set_by_name_d2r(save.character.class, "Bash", 20).is_err() {
53        save.skills.set(0, 20);
54    }
55    if save.skills.set_by_name_d2r(save.character.class, "Battle Orders", 20).is_err() {
56        save.skills.set(23, 20);
57    }
58    if save.skills.set_by_name_d2r(save.character.class, "Whirlwind", 20).is_err() {
59        save.skills.set(25, 20);
60    }
61
62    // Give Act I all waypoints.
63    save.waypoints.normal.act1.set_all(true);
64
65    // Edit one quest state.
66    save.quests.normal.act1.q1.state.insert(QuestFlag::Started);
67
68    let act1_catacombs = save.waypoints.normal.act1.get_by_index(8)?;
69    let quest_started = save.quests.normal.act1.q1.state.contains(&QuestFlag::Started);
70
71    // Write back to the same detected format.
72    let output_bytes = save.encode_for(target_format, CompatibilityChecks::Enforce)?;
73    std::fs::create_dir_all(output_dir)?;
74    std::fs::write(&output_path, output_bytes)?;
75
76    println!("Wrote {output_path}");
77    println!("Now: {} / lvl {}", save.character.name, save.character.level());
78    println!(
79        "Stats: str={} dex={} vit={} ene={}",
80        save.attributes.strength.value,
81        save.attributes.dexterity.value,
82        save.attributes.vitality.value,
83        save.attributes.energy.value
84    );
85    println!(
86        "Resources: hp={} mana={} stamina={}",
87        save.attributes.get_max_hp(),
88        save.attributes.get_max_mana(),
89        save.attributes.get_max_stamina()
90    );
91    println!("Act I / Catacombs waypoint: {act1_catacombs}");
92    println!("Quest q1 started: {quest_started}");
93
94    Ok(())
95}
Source

pub fn summarize( byte_slice: &[u8], strictness: Strictness, ) -> Result<SaveSummary, ParseHardError>

Summarize only top-level header + character fields.

Source

pub fn encode_for( &self, format: FormatId, compatibility_checks: CompatibilityChecks, ) -> Result<Vec<u8>, EncodeError>

Encode to a specific output format with an explicit compatibility policy.

Examples found in repository?
examples/edit_character.rs (line 72)
4fn main() -> Result<(), Box<dyn std::error::Error>> {
5    let input_path = "assets/test/Warlock_v105.d2s";
6    let output_name = "WarlockDemo";
7    let output_dir = "target/example-output";
8    let output_path = format!("{output_dir}/{output_name}.d2s");
9
10    let bytes = std::fs::read(input_path)?;
11    let parsed = Save::parse(&bytes, Strictness::Strict)?;
12    if !parsed.issues.is_empty() {
13        return Err(format!("fixture parsed with issues: {:?}", parsed.issues).into());
14    }
15
16    let mut save = parsed.save;
17    let target_format = save.format();
18
19    println!(
20        "Loaded {:?} / {} / lvl {}",
21        target_format,
22        save.character.name,
23        save.character.level()
24    );
25
26    // Keep the file name and in-game name aligned.
27    save.character.name = output_name.to_string();
28
29    // Keep character.level and attributes.level in sync.
30    save.set_level(75);
31
32    // Main stats.
33    save.attributes.strength.value = 220;
34    save.attributes.dexterity.value = 175;
35    save.attributes.vitality.value = 260;
36    save.attributes.energy.value = 110;
37    save.attributes.statpts.value = 25;
38    save.attributes.newskills.value = 10;
39    save.attributes.gold.value = 200_000;
40    save.attributes.goldbank.value = 2_500_000;
41
42    // These stats are fixed-point in the save file (Q8), so the helpers take in-game values.
43    save.attributes.set_max_hp(2200);
44    save.attributes.set_hp(2200);
45    save.attributes.set_max_mana(900);
46    save.attributes.set_mana(900);
47    save.attributes.set_max_stamina(1200);
48    save.attributes.set_stamina(1200);
49
50    // Use the D2R name lookup when it exists.
51    // Fall back to raw slot indexes when it does not.
52    if save.skills.set_by_name_d2r(save.character.class, "Bash", 20).is_err() {
53        save.skills.set(0, 20);
54    }
55    if save.skills.set_by_name_d2r(save.character.class, "Battle Orders", 20).is_err() {
56        save.skills.set(23, 20);
57    }
58    if save.skills.set_by_name_d2r(save.character.class, "Whirlwind", 20).is_err() {
59        save.skills.set(25, 20);
60    }
61
62    // Give Act I all waypoints.
63    save.waypoints.normal.act1.set_all(true);
64
65    // Edit one quest state.
66    save.quests.normal.act1.q1.state.insert(QuestFlag::Started);
67
68    let act1_catacombs = save.waypoints.normal.act1.get_by_index(8)?;
69    let quest_started = save.quests.normal.act1.q1.state.contains(&QuestFlag::Started);
70
71    // Write back to the same detected format.
72    let output_bytes = save.encode_for(target_format, CompatibilityChecks::Enforce)?;
73    std::fs::create_dir_all(output_dir)?;
74    std::fs::write(&output_path, output_bytes)?;
75
76    println!("Wrote {output_path}");
77    println!("Now: {} / lvl {}", save.character.name, save.character.level());
78    println!(
79        "Stats: str={} dex={} vit={} ene={}",
80        save.attributes.strength.value,
81        save.attributes.dexterity.value,
82        save.attributes.vitality.value,
83        save.attributes.energy.value
84    );
85    println!(
86        "Resources: hp={} mana={} stamina={}",
87        save.attributes.get_max_hp(),
88        save.attributes.get_max_mana(),
89        save.attributes.get_max_stamina()
90    );
91    println!("Act I / Catacombs waypoint: {act1_catacombs}");
92    println!("Quest q1 started: {quest_started}");
93
94    Ok(())
95}
Source

pub fn check_compatibility(&self, target: FormatId) -> Vec<CompatibilityIssue>

Return compatibility findings for encoding this save to target.

Source

pub fn title_d2r(&self) -> Option<&'static str>

Return the default D2R title for this save using the canonical expansion mode.

Source

pub fn validate(&self) -> ValidationReport

Validate the current save using backend-owned canonical rules.

Examples found in repository?
examples/inspect_issues.rs (line 16)
3fn main() -> Result<(), Box<dyn std::error::Error>> {
4    // Start from a known good file.
5    let bytes = std::fs::read("assets/test/Joe.d2s")?;
6
7    // Strict mode fails fast on invalid data.
8    let strict = Save::parse(&bytes, Strictness::Strict)?;
9    println!(
10        "Strict parse OK: format={:?}, name={}",
11        strict.save.format(),
12        strict.save.character.name
13    );
14
15    // Validation is separate from parsing, so check the save on its own.
16    let validation = strict.save.validate();
17    println!("\nValidation issues: {}", validation.issues.len());
18    for (index, issue) in validation.issues.iter().enumerate() {
19        println!("#{index} [{:?}] {}", issue.code, issue.message);
20    }
21
22    // Break the payload on purpose so we can inspect non-fatal issues.
23    // - byte 0 breaks signature
24    // - truncation simulates a damaged or incomplete file
25    let mut damaged = bytes.clone();
26    damaged[0] = 0x00;
27    damaged.truncate(220);
28
29    // Lax mode keeps going and collects issues.
30    let lax = Save::parse(&damaged, Strictness::Lax)?;
31    println!("\nLax parse issues: {}", lax.issues.len());
32    for (index, issue) in lax.issues.iter().enumerate() {
33        println!(
34            "#{index} [{:?}/{:?}] section={:?} offset={:?} expected={:?} found={:?}\n  {}",
35            issue.severity,
36            issue.kind,
37            issue.section,
38            issue.offset,
39            issue.expected,
40            issue.found,
41            issue.message
42        );
43    }
44
45    // Strict mode should reject the damaged payload.
46    match Save::parse(&damaged, Strictness::Strict) {
47        Ok(_) => println!("\nUnexpected: strict parse accepted damaged payload."),
48        Err(error) => println!("\nStrict parse error: {error}"),
49    }
50
51    Ok(())
52}

Trait Implementations§

Source§

impl Clone for Save

Source§

fn clone(&self) -> Save

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for Save

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Default for Save

Source§

fn default() -> Self

Returns the “default value” for a type. Read more
Source§

impl<'de> Deserialize<'de> for Save

Source§

fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>
where __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
Source§

impl Display for Save

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl PartialEq for Save

Source§

fn eq(&self, other: &Save) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
Source§

impl Serialize for Save

Source§

fn serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error>
where __S: Serializer,

Serialize this value into the given Serde serializer. Read more
Source§

impl Eq for Save

Source§

impl StructuralPartialEq for Save

Auto Trait Implementations§

§

impl Freeze for Save

§

impl RefUnwindSafe for Save

§

impl Send for Save

§

impl Sync for Save

§

impl Unpin for Save

§

impl UnsafeUnpin for Save

§

impl UnwindSafe for Save

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T> ToString for T
where T: Display + ?Sized,

Source§

fn to_string(&self) -> String

Converts the given value to a String. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> DeserializeOwned for T
where T: for<'de> Deserialize<'de>,