Isso é seguro?
Suponha que eu queira chamar algum código Rust de dentro do Python . Suponha que minha lib.rs
aparência seja algo assim:
#[no_mangle]
pub extern fn add(left: i32, right: i32) -> i32 {
return left+right;
}
E suponho que chamei esse código do Python usando ctypes
assim:
import ctypes
def rust_add(left, right):
rust_lib = ctypes.CDLL("path/to/the/so/file")
return rust_lib.add(left, right)
Então o acima é seguro?
Um obstáculo antecipado: estouro de número inteiro
Estouro nas entradas
Um problema que até eu - com meu conhecimento extremamente tênue de Rust - posso prever é o estouro de inteiros . Imagino que, se left
ou right
fosse maior que 2 ^ 32, isso faria com que coisas ruins acontecessem: ou Rust atingia um erro de tempo de execução (provavelmente) ou apenas retornaria respostas bobas (pior caso). Alguma verificação de tipo no Python, talvez usando NumPy's uint32
, seria suficiente para evitar esse problema?
Estouro no funcionamento
Este é mais insidioso: suponha que eu peça, do Python, à minha função Rust para adicionar (2^32)-1 e (2^32)-2. Não deve haver nenhum excesso imediato, mas haverá quando somarmos os dois números. Pelo que entendi, ao atingir tal estouro, Rust entrará em pânico no modo de depuração, mas tentará o seu melhor para continuar no modo de liberação.
Resumo
- Existe alguma prática bem conhecida para suavizar as dificuldades que surgem ao passar números inteiros entre uma linguagem de largura dinâmica, como Python, e uma de largura fixa, como Rust, além de testes completos?
- Há algum problema com a passagem de números inteiros entre Rust e Python, além do estouro de números inteiros?
Por padrão,
ctypes
irá converter parâmetros inteiros e valores de retorno de função para seuc_int
tipo, cujo tamanho depende da plataforma. Valores que excedam esse tamanho serão truncados. Sec_int
não tiver 32 bits, isso levaria a um comportamento indefinido no sentido Rust (você acaba chamando a função Rust com uma convenção de chamada incorreta). Provavelmente não é isso que você deseja neste caso. (É certo quec_int
é de 32 bits nas plataformas de desktop mais comuns).Eu ainda recomendo o seguinte código python:
Dessa forma,
ctypes
converterá argumentos e tipos de retorno para o tipo inteiro correto, independentemente da plataforma.Ele ainda truncará números inteiros maiores e lançará uma exceção para outros tipos de python. Se você quiser ter uma maneira diferente de lidar com esses casos, terá que fazer isso sozinho. Para obter mais detalhes sobre como as conversões de tipo são tratadas,
ctypes
recomendo sua excelente documentação .Se você quiser apenas ter certeza de que os valores passados são corretos e obter algum tipo de exceção em todos os outros casos, você pode escrever uma função simples como esta:
Em relação aos overflows no lado do Rust: eles seguirão as regras usuais de overflow de inteiros do Rust (pânico na depuração, complemento de dois no lançamento). Se não é isso que você deseja, codifique alguma outra lógica.