repo_description: This is the Rust course used by the Android team at Google. It provides you the material to quickly teach Rust.
repo_topics: android classroom course google guide rust training training-materials
code: // Copyright 2026 Google LLC
  // SPDX-License-Identifier: Apache-2.0
  //
  // Licensed under the Apache License, Version 2.0 (the "License");
  // you may not use this file except in compliance with the License.
  // You may obtain a copy of the License at
  //
  //      http://www.apache.org/licenses/LICENSE-2.0
  //
  // Unless required by applicable law or agreed to in writing, software
  // distributed under the License is distributed on an "AS IS" BASIS,
  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  // See the License for the specific language governing permissions and
  // limitations under the License.
  
  // ANCHOR: solution
  // ANCHOR: setup
  struct Spell {
      name: String,
      cost: u32,
      uses: u32,
  }
  
  struct Wizard {
      spells: Vec<Spell>,
      mana: u32,
  }
  
  impl Wizard {
      fn new(mana: u32) -> Self {
          Wizard { spells: vec![], mana }
      }
      // ANCHOR_END: setup
  
      fn add_spell(&mut self, spell: Spell) {
          self.spells.push(spell);
      }
  
      fn cast_spell(&mut self, name: &str) {
          let mut spell_idx = None;
          for idx in 0..self.spells.len() {
              if self.spells[idx].name == name {
                  spell_idx = Some(idx);
                  break;
              }
          }
  
          let Some(idx) = spell_idx else {
              println!("Spell {} not found!", name);
              return;
          };
  
          let spell = &mut self.spells[idx];
          if self.mana >= spell.cost {
              self.mana -= spell.cost;
              spell.uses -= 1;
              println!(
                  "Casting {}! Mana left: {}. Uses left: {}",
                  spell.name, self.mana, spell.uses
              );
              if spell.uses == 0 {
                  self.spells.remove(idx);
              }
          } else {
              println!("Not enough mana to cast {}!", spell.name);
          }
      }
  }
  
  // ANCHOR: main
  fn main() {
      let mut merlin = Wizard::new(100);
      let fireball = Spell { name: String::from("Fireball"), cost: 10, uses: 2 };
      let ice_blast = Spell { name: String::from("Ice Blast"), cost: 15, uses: 1 };
  
      merlin.add_spell(fireball);
      merlin.add_spell(ice_blast);
  
      merlin.cast_spell("Fireball"); // Casts successfully
      merlin.cast_spell("Ice Blast"); // Casts successfully, then removed
      merlin.cast_spell("Ice Blast"); // Fails (not found)
      merlin.cast_spell("Fireball"); // Casts successfully, then removed
      merlin.cast_spell("Fireball"); // Fails (not found)
  }
  // ANCHOR_END: main
  
  // ANCHOR: tests
  #[cfg(test)]
  mod tests {
      use super::*;
  
      #[test]
      fn test_add_spell() {
          let mut wizard = Wizard::new(10);
          let spell = Spell { name: String::from("Fireball"), cost: 5, uses: 3 };
          wizard.add_spell(spell);
          assert_eq!(wizard.spells.len(), 1);
      }
  
      #[test]
      fn test_cast_spell() {
          let mut wizard = Wizard::new(10);
          let spell = Spell { name: String::from("Fireball"), cost: 5, uses: 3 };
          wizard.add_spell(spell);
  
          wizard.cast_spell("Fireball");
          assert_eq!(wizard.mana, 5);
          assert_eq!(wizard.spells.len(), 1);
          assert_eq!(wizard.spells[0].uses, 2);
      }
  
      #[test]
      fn test_cast_spell_insufficient_mana() {
          let mut wizard = Wizard::new(10);
          let spell = Spell { name: String::from("Fireball"), cost: 15, uses: 3 };
          wizard.add_spell(spell);
  
          wizard.cast_spell("Fireball");
          assert_eq!(wizard.mana, 10);
          assert_eq!(wizard.spells.len(), 1);
          assert_eq!(wizard.spells[0].uses, 3);
      }
  
      #[test]
      fn test_cast_spell_not_found() {
          let mut wizard = Wizard::new(10);
          wizard.cast_spell("Fireball");
          assert_eq!(wizard.mana, 10);
      }
  
      #[test]
      fn test_cast_spell_removal() {
          let mut wizard = Wizard::new(10);
          let spell = Spell { name: String::from("Fireball"), cost: 5, uses: 1 };
          wizard.add_spell(spell);
  
          wizard.cast_spell("Fireball");
          assert_eq!(wizard.mana, 5);
          assert_eq!(wizard.spells.len(), 0);
      }
  }
  // ANCHOR_END: tests
  