trion 0.7.2

Trion is an assembler designed to be used with the Raspberry Pico (RP2040) microcontroller.
Documentation
use core::fmt::{self, Write};

use crate::arm6m::reg::Register;

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct RegisterSet(u16);

impl RegisterSet
{
	pub fn new() -> Self
	{
		Self(0)
	}
	
	pub fn of(value: u16) -> Self
	{
		Self(value)
	}
	
	pub fn is_empty(&self) -> bool
	{
		self.0 == 0
	}
	
	pub fn count(&self) -> usize
	{
		self.0.count_ones() as usize
	}
	
	pub fn add(&mut self, reg: Register) -> bool
	{
		let mask = 1 << u8::from(reg);
		let changed = (self.0 & mask) == 0;
		self.0 |= mask;
		changed
	}
	
	pub fn set_bits(&mut self, bits: u16) -> u16
	{
		let prev = !self.0 & bits;
		self.0 |= bits;
		prev
	}
	
	pub fn remove(&mut self, reg: Register) -> bool
	{
		let mask = 1 << u8::from(reg);
		let changed = (self.0 & mask) != 0;
		self.0 &= !mask;
		changed
	}
	
	pub fn unset_bits(&mut self, bits: u16) -> u16
	{
		let prev = self.0 & bits;
		self.0 &= !bits;
		prev
	}
	
	pub fn contains(&self, reg: Register) -> bool
	{
		(self.0 & (1 << u8::from(reg))) != 0
	}
	
	pub fn get_bits(&self) -> u16
	{
		self.0
	}
	
	pub fn iter(&self) -> RegIter
	{
		if self.0 > 0
		{
			let first = self.0.trailing_zeros();
			RegIter{next: Some(first as u8), more: self.0.checked_shr(first + 1).unwrap_or(0)}
		}
		else {RegIter{next: None, more: 0}}
	}
	
	pub fn clear(&mut self)
	{
		self.0 = 0;
	}
}

impl fmt::Display for RegisterSet
{
	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result 
	{
		f.write_char('{')?;
		let mut first = true;
		for i in 0..16u8
		{
			if ((self.0 >> i) & 1) != 0
			{
				if !first {f.write_str(", ")?;}
				Register::try_from(i).unwrap().fmt(f)?;
				first = false;
			}
		}
		f.write_char('}')
	}
}

impl IntoIterator for RegisterSet
{
	type Item = Register;
	type IntoIter = RegIter;
	
	fn into_iter(self) -> Self::IntoIter
	{
		self.iter()
	}
}

pub struct RegIter
{
	next: Option<u8>,
	more: u16,
}

impl Iterator for RegIter
{
	type Item = Register;
	
	fn next(&mut self) -> Option<Self::Item>
	{
		match self.next
		{
			None => None,
			Some(curr) =>
			{
				self.next = if self.more > 0
				{
					let dist = self.more.trailing_zeros() + 1;
					self.more = self.more.checked_shr(dist).unwrap_or(0);
					Some(curr + dist as u8)
				}
				else {None};
				Some(Register::try_from(curr).unwrap())
			},
		}
	}
	
	fn size_hint(&self) -> (usize, Option<usize>)
	{
		if self.next.is_some()
		{
			let cnt = 1 + self.more.count_ones() as usize;
			(cnt, Some(cnt))
		}
		else {(0, Some(0))}
	}
}