user.rs 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475
  1. use steel::*;
  2. use crate::error::{CloseAccountError, CloseAccountResult};
  3. /// An enum which is used to derive a discriminator for the user account.
  4. #[repr(u8)]
  5. #[derive(Clone, Copy, Debug, Eq, PartialEq, IntoPrimitive, TryFromPrimitive)]
  6. pub enum UserAccount {
  7. /// The user is represented by a discriminator of `0`
  8. User = 0,
  9. }
  10. /// The user Account structure which stores a
  11. /// `name` as bytes with max array length of u64 due to the
  12. /// requirement for memory alignment since 64 is a factor of 8.
  13. #[repr(C)]
  14. #[derive(Clone, Copy, Debug, PartialEq, Pod, Zeroable)]
  15. pub struct User {
  16. /// The name string stored as bytes.
  17. /// The `&str` is converted into bytes and copied upto
  18. /// the length of the bytes, if the bytes are not 64, it
  19. /// pads with zeroes upto 64, if it is more than 64 an error
  20. /// is returned.
  21. pub name: [u8; 64],
  22. }
  23. impl User {
  24. /// Seed for the [User] used to in PDA generation
  25. pub const SEED_PREFIX: &'static str = "USER";
  26. /// Create a new user, convert the name into bytes
  27. /// and add those bytes to a 64 byte array
  28. pub fn new(name: &str) -> CloseAccountResult<Self> {
  29. let name_bytes = name.as_bytes();
  30. Self::check_length(name_bytes)?;
  31. let mut name = [0u8; 64];
  32. name[0..name_bytes.len()].copy_from_slice(name_bytes);
  33. Ok(Self { name })
  34. }
  35. /// Converts the byte array into a UTF-8 [str]
  36. /// using the `trim_end_matches("\0")` of [str] method
  37. /// to remove padded zeroes if any. Padded zeroes are
  38. /// represented by `\0`
  39. pub fn to_string(&self) -> CloseAccountResult<String> {
  40. let value =
  41. core::str::from_utf8(&self.name).map_err(|_| CloseAccountError::OnlyUtf8IsSupported)?;
  42. Ok(value.trim_end_matches("\0").to_string())
  43. }
  44. fn check_length(bytes: &[u8]) -> CloseAccountResult<()> {
  45. if bytes.len() > 64 {
  46. return Err(CloseAccountError::MaxNameLengthExceeded);
  47. }
  48. Ok(())
  49. }
  50. /// Generate a PDA from the [Self::SEED_PREFIX] constant
  51. /// and the payer public key. This returns a tuple struct
  52. /// ([Pubkey], [u8])
  53. pub fn pda(payer: Pubkey) -> (Pubkey, u8) {
  54. Pubkey::try_find_program_address(
  55. &[Self::SEED_PREFIX.as_bytes(), payer.as_ref()],
  56. &crate::id(),
  57. )
  58. .unwrap()
  59. }
  60. }
  61. account!(UserAccount, User);