# Usage de ksp-program-api Cette page décrit la surface publique disponible à partir de `0.2.14-pre.004`. Utiliser uniquement les exports du crate-root ; aucun module interne ne fait partie du contrat consommable. ## Construire un input Program avec la façade ```rust let program_id = ksp_program_api::Pubkey::new_from_array([1_u8; 32]); let account_id = ksp_program_api::Pubkey::new_from_array([2_u8; 32]); let account = ksp_program_api::ProgramAccountMeta::readonly(account_id, true); let instruction = ksp_program_api::ProgramInstruction::try_new( program_id, std::vec![account], std::vec![0x01_u8, 0x02, 0x03], ); assert!(instruction.is_ok()); ``` `Pubkey`, `ProgramAccountMeta` et `ProgramInstruction` conservent leur ownership Core/Interface. ## Implémenter un decoder externe Le type décodé reste entièrement possédé par la crate d'implémentation : ```rust struct ExternalDecodedInstruction { opcode: u8, } struct ExternalDecoder { program_ids: [ksp_program_api::Pubkey; 1], } impl ksp_program_api::ProgramInstructionDecoder for ExternalDecoder { type Decoded = ExternalDecodedInstruction; fn program_ids(&self) -> &[ksp_program_api::Pubkey] { return &self.program_ids; } fn recognize( &self, instruction: &ksp_program_api::ProgramInstruction, ) -> ksp_program_api::ProgramInstructionRecognition { if instruction.program_id() != &self.program_ids[0] { return ksp_program_api::ProgramInstructionRecognition::NoMatch; } return ksp_program_api::ProgramInstructionRecognition::ProgramMatch; } fn decode( &self, instruction: &ksp_program_api::ProgramInstruction, ) -> ksp_program_api::Result> { let opcode = match instruction.data().first() { std::option::Option::Some(value) => *value, std::option::Option::None => { return std::result::Result::Ok( ksp_program_api::ProgramInstructionDecodeOutcome::Unsupported, ); } }; return std::result::Result::Ok( ksp_program_api::ProgramInstructionDecodeOutcome::Decoded( ExternalDecodedInstruction { opcode }, ), ); } } ``` Aucun `ksp-program-lib`, enum centrale, `Any`, JSON ou codec n'est nécessaire. Le Program ID peut être un `Pubkey` opaque non enregistré par Core. ## Sélection explicite La sélection reste distincte du décodage : ```rust let recognition = ksp_program_api::ProgramInstructionDecoder::recognize( &decoder, &instruction, ); match recognition { ksp_program_api::ProgramInstructionRecognition::NoMatch => {} ksp_program_api::ProgramInstructionRecognition::ProgramMatch => {} ksp_program_api::ProgramInstructionRecognition::ExactMatch => {} _ => {} } ``` L'enum est `#[non_exhaustive]`. `decode` n'est pas un substitut à `recognize` : il traite une instruction déjà sélectionnée pour le decoder. ## Outcome et erreur ```rust let outcome = ksp_program_api::ProgramInstructionDecoder::decode( &decoder, &instruction, )?; match outcome { ksp_program_api::ProgramInstructionDecodeOutcome::Decoded(value) => { let _opcode = value.opcode; } ksp_program_api::ProgramInstructionDecodeOutcome::Unsupported => {} _ => {} } ``` Une erreur réelle est un `Err(ksp_program_api::Error)`. `Unsupported` n'est pas une deuxième forme d'erreur : il indique qu'une instruction reconnue n'est volontairement pas décodée par cette capability. ## Debug sûr `ProgramInstructionDecodeOutcome` possède un `Debug` volontairement opaque : ```rust struct SecretDecoded; let outcome = ksp_program_api::ProgramInstructionDecodeOutcome::Decoded(SecretDecoded); assert_eq!(std::format!("{outcome:?}"), "Decoded"); ``` `SecretDecoded` n'a pas besoin d'implémenter `Debug` et sa valeur n'est jamais rendue par l'outcome. ## Hors surface `pre.004` Il n'existe toujours aucun : ```text registry de decoders composition dyn hétérogène identity/version/coverage descriptor payload canonique D3 ProgramAccountDecoder / Event / ReturnData ProgramExecutionPreparer execution policy serde / JSON / codec logging / runtime réseau ``` Ces surfaces ne doivent pas être simulées côté consumer. Elles attendent les vertical slices qui justifieront leurs contrats réels.