IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Voir le flux RSS

nothus

[Pense-bête] Rust / Python : le cas des strings / str (chaîne de caractères)

Noter ce billet
par , 05/03/2020 à 14h12 (485 Affichages)
Pour ce pense-bête, penchons-nous tout d'abord dans un nouveau projet :

... en pensant à ajouter dans le fichier toml de ce projet :

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
[lib]
name = "projet"
crate-type = ["dylib"]
... et éditer le fichier (préalablement créé) lib.rs dans le dossier ./src :

Code rust : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
use std::ffi::CString; 
use std::ffi::CStr; 
use std::os::raw::c_char; 
 
#[no_mangle] // 
pub extern fn depuis_rust() -> *const c_char {
    let s = CString::new("& oui").unwrap();
    let p = s.as_ptr(); 
    std::mem::forget(s); 
    p 
} 
 
#[no_mangle]
pub extern fn vers_rust( texte: *const c_char) -> *const c_char { 
    let cstr = unsafe { 
        CStr::from_ptr( texte ) 
    }; 
    let string = cstr.to_str().expect("chaine UTF-8 invalide");
    println!("{}", string); 
    let s = CString::new("@ maison").unwrap();
    let p = s.as_ptr();
    std::mem::forget(s);
    p 
}

... puis lancer la compilation :

Vous obtenez le fichier .so correspondant. Éditons maintenant le fichier .py qui utilisera cette bibliothèque :

Code python3 : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import ctypes 

lib = ctypes.cdll.LoadLibrary("./target/release/libembed.so")

l = lib.depuis_rust() 

print( ctypes.c_char_p( l ).value ) 

l2 = lib.vers_rust( 
    ctypes.c_char_p( 
        "tout ça : ²&é\"'(-è_çà)=".encode('utf-8') 
    ) 
) 

print( ctypes.c_char_p( l2 ).value )

L'exécution du script Python devrait retourner alors les chaînes attendues :

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
b'& oui'
tout ça : ²&é"'(-è_çà)=
b'@ maison'
Quelques observations :
  • la gestion des chaînes "via" le format utilisé par C (le caractère \0 en fin de chaîne) ;
  • l'usage "natif" d'UTF-8 ;
  • l'inadéquation de la gestion habituelle de Rust sur du texte (vecteur) avec ce qui est supporté par ctypes dans Python (évolution à venir ?) ;
  • l'entête "no_mangle" (aucune mutilation) dans Rust, permet de respecter les standards du C lors de la compilation.


Un dernier point : l'usage de std::mem::forget peut sembler singulier au sein de depuis_rust. On demande explicitement "l'oubli" de la variable "s" dont on a demandé le pointeur juste avant (et on retourne ce pointeur). Pourquoi un tel comportement ? L'explication est logique : il s'agit d'abord de préserver l'intégrité des règles (de toute façon incontournables...) de Rust - qui est aussi sa sécurité et sa force.
La variable "s" utilisée ici, est liée au contexte de la fonction. L'usage de std::mem::forget "libère" en quelque sorte le pointeur, et peut donc être utilisée ailleurs (cf. règle de propriété / partage).

Voir aussi :

Envoyer le billet « [Pense-bête] Rust / Python : le cas des strings / str (chaîne de caractères) » dans le blog Viadeo Envoyer le billet « [Pense-bête] Rust / Python : le cas des strings / str (chaîne de caractères) » dans le blog Twitter Envoyer le billet « [Pense-bête] Rust / Python : le cas des strings / str (chaîne de caractères) » dans le blog Google Envoyer le billet « [Pense-bête] Rust / Python : le cas des strings / str (chaîne de caractères) » dans le blog Facebook Envoyer le billet « [Pense-bête] Rust / Python : le cas des strings / str (chaîne de caractères) » dans le blog Digg Envoyer le billet « [Pense-bête] Rust / Python : le cas des strings / str (chaîne de caractères) » dans le blog Delicious Envoyer le billet « [Pense-bête] Rust / Python : le cas des strings / str (chaîne de caractères) » dans le blog MySpace Envoyer le billet « [Pense-bête] Rust / Python : le cas des strings / str (chaîne de caractères) » dans le blog Yahoo

Commentaires