v0.2.14-pre.004

This commit is contained in:
2026-08-28 14:21:21 +02:00
parent 27d4cb1f36
commit bcf2f16c05
11 changed files with 649 additions and 89 deletions

View File

@@ -1,9 +1,9 @@
<!-- file: crates/ksp-program-api/USAGE.md -->
<!-- version: 2 -->
<!-- version: 3 -->
# Usage de ksp-program-api
Cette page décrit la surface publique disponible à partir de `0.2.14-pre.003`. Utiliser uniquement les exports du crate-root ; aucun module interne ne fait partie du contrat consommable.
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
@@ -21,12 +21,70 @@ let instruction = ksp_program_api::ProgramInstruction::try_new(
assert!(instruction.is_ok());
```
`Pubkey`, `ProgramAccountMeta` et `ProgramInstruction` conservent leur ownership Core/Interface. Program API fournit seulement une façade cohérente aux futures implémentations de capability Program.
`Pubkey`, `ProgramAccountMeta` et `ProgramInstruction` conservent leur ownership Core/Interface.
## Représenter une reconnaissance
## Implémenter un decoder externe
Le type décodé reste entièrement possédé par la crate d'implémentation :
```rust
let recognition = ksp_program_api::ProgramInstructionRecognition::ProgramMatch;
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<ksp_program_api::ProgramInstructionDecodeOutcome<Self::Decoded>> {
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 => {}
@@ -36,35 +94,30 @@ match recognition {
}
```
Le wildcard est volontaire : l'enum est `#[non_exhaustive]` afin de ne pas transformer la foundation en vocabulaire fermé pour toujours.
L'enum est `#[non_exhaustive]`. `decode` n'est pas un substitut à `recognize` : il traite une instruction déjà sélectionnée pour le decoder.
## Représenter un outcome de décodage
Le type décodé reste possédé par l'implémentation :
## Outcome et erreur
```rust
struct ExternalDecodedInstruction {
opcode: u8,
}
let outcome = ksp_program_api::ProgramInstructionDecodeOutcome::Decoded(
ExternalDecodedInstruction { opcode: 7_u8 },
);
let outcome = ksp_program_api::ProgramInstructionDecoder::decode(
&decoder,
&instruction,
)?;
match outcome {
ksp_program_api::ProgramInstructionDecodeOutcome::Decoded(value) => {
assert_eq!(value.opcode, 7_u8);
let _opcode = value.opcode;
}
ksp_program_api::ProgramInstructionDecodeOutcome::Unsupported => {}
_ => {}
}
```
Aucun `Any`, JSON ou enum centrale n'est nécessaire pour transporter ce type.
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<Decoded>` possède un `Debug` volontairement opaque sur la valeur décodée :
`ProgramInstructionDecodeOutcome<Decoded>` possède un `Debug` volontairement opaque :
```rust
struct SecretDecoded;
@@ -73,34 +126,22 @@ let outcome = ksp_program_api::ProgramInstructionDecodeOutcome::Decoded(SecretDe
assert_eq!(std::format!("{outcome:?}"), "Decoded");
```
`SecretDecoded` n'a même pas besoin d'implémenter `Debug`. Cela empêche un diagnostic générique de rendre accidentellement un payload externe.
`SecretDecoded` n'a pas besoin d'implémenter `Debug` et sa valeur n'est jamais rendue par l'outcome.
## Utiliser le contrat d'erreur commun
## Hors surface `pre.004`
Les types d'erreur Core restent disponibles depuis la façade :
```rust
fn forward_result(
value: ksp_program_api::Result<ksp_program_api::ProgramInstruction>,
) -> ksp_program_api::Result<ksp_program_api::ProgramInstruction> {
return value;
}
```
Le futur `decode(...)` utilisera ce `Result`. Une erreur sera donc `Err(...)`, tandis que `Unsupported` signifie une instruction connue volontairement non prise en charge.
## Ce que `pre.003` ne fournit pas
Il n'existe encore aucun :
Il n'existe toujours aucun :
```text
ProgramInstructionDecoder
program_ids(...)
recognize(...) sur un trait
decode(...) sur un trait
registry de decoders
payload générique JSON/Any
execution preparer
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 éléments ne doivent pas être simulés côté consumer. Le trait decoder et la preuve d'implémentation externe sont réservés à `pre.004`.
Ces surfaces ne doivent pas être simulées côté consumer. Elles attendent les vertical slices qui justifieront leurs contrats réels.