xprogram 0.1.0

program for testing
Documentation
use crate::util::str_pack;
use solana_program::pubkey::Pubkey;
use solana_program::{
    instruction::AccountMeta, instruction::Instruction, program_error::ProgramError,
};
use std::mem::size_of;
use std::str::from_utf8;

pub enum TopicInstruction<'a> {
    CreateTopic {
        topic_name: &'a str,
        option_name: &'a str,
    },
    AddOption {
        option_name: &'a str,
    },
    VoteTopic {
        opt_idx: u8,
    },
    FinishTopic,
}

impl<'a> TopicInstruction<'a> {
    pub fn unpack(input: &'a [u8]) -> Result<Self, ProgramError> {
        use ProgramError::InvalidInstructionData;
        let (&tag, rest) = input.split_first().ok_or(InvalidInstructionData)?;

        Ok(match tag {
            0 => {
                let mut split_index: usize = 0;
                for (i, char) in rest.iter().enumerate() {
                    if *char == '|' as u8 {
                        split_index = i;
                        break;
                    }
                }
                let (topic_name, option_name) = rest.split_at(split_index);
                let (_, option_name) = option_name.split_first().ok_or(InvalidInstructionData)?;
                let topic_name = from_utf8(topic_name).unwrap();
                let option_name = from_utf8(option_name).unwrap();
                Self::CreateTopic {
                    topic_name,
                    option_name,
                }
            }
            1 => {
                let option_name = from_utf8(rest).unwrap();
                Self::AddOption { option_name }
            }
            2 => {
                let opt_idx = rest[0];
                Self::VoteTopic { opt_idx }
            }
            3 => Self::FinishTopic,
            _ => return Err(InvalidInstructionData),
        })
    }

    pub fn pack(&self) -> Vec<u8> {
        let mut buf: Vec<u8> = Vec::with_capacity(size_of::<Self>());
        match *self {
            Self::CreateTopic {
                topic_name,
                option_name,
            } => {
                buf.push(0);
                buf.extend_from_slice(topic_name.as_bytes());
                buf.push('|' as u8);
                buf.extend_from_slice(option_name.as_bytes());
            }
            Self::AddOption { option_name } => {
                buf.push(1);
                buf.extend_from_slice(option_name.as_bytes());
            }
            Self::VoteTopic { opt_idx } => {
                buf.push(2);
                buf.push(opt_idx);
            }
            Self::FinishTopic => {
                buf.push(3);
            }
        }
        buf
    }
}

pub fn create_topic(
    program_id: &Pubkey,
    topic: &Pubkey,
    topic_owner: &Pubkey,
    topic_name: &str,
    option_name: &str,
) -> Result<Instruction, ProgramError> {
    let data = TopicInstruction::CreateTopic {
        topic_name,
        option_name,
    }
    .pack();
    let accounts = vec![
        AccountMeta::new(*topic, false),
        AccountMeta::new(*topic_owner, true),
    ];

    Ok(Instruction {
        program_id: *program_id,
        accounts,
        data,
    })
}

pub fn add_option(
    program_id: &Pubkey,
    topic: &Pubkey,
    option_adder: &Pubkey,
    option_name: &str,
) -> Result<Instruction, ProgramError> {
    let data = TopicInstruction::AddOption { option_name }.pack();
    let accounts = vec![
        AccountMeta::new(*topic, false),
        AccountMeta::new(*option_adder, true),
    ];

    Ok(Instruction {
        program_id: *program_id,
        accounts,
        data,
    })
}

pub fn vote_topic(
    program_id: &Pubkey,
    topic: &Pubkey,
    voter: &Pubkey,
    opt_idx: u8,
) -> Result<Instruction, ProgramError> {
    let data = TopicInstruction::VoteTopic { opt_idx }.pack();
    let accounts = vec![
        AccountMeta::new(*topic, false),
        AccountMeta::new(*voter, true),
    ];

    Ok(Instruction {
        program_id: *program_id,
        accounts,
        data,
    })
}

pub fn finish_topic(
    program_id: &Pubkey,
    topic: &Pubkey,
    topic_owner: &Pubkey,
) -> Result<Instruction, ProgramError> {
    let data = TopicInstruction::FinishTopic.pack();
    let accounts = vec![
        AccountMeta::new(*topic, false),
        AccountMeta::new(*topic_owner, true),
    ];

    Ok(Instruction {
        program_id: *program_id,
        accounts,
        data,
    })
}