2015-05-18 12 views
10

पर पाइथन सूची पास करें मैं पाइथन में जंग कार्यों को एम्बेड करने के तरीके सीख रहा हूं, और यदि मेरे इनपुट int एस हैं, लेकिन सूची नहीं है, तो सब ठीक काम करता है।एम्बेडेड जंग फंक्शन

अगर मेरे lib.rs फ़ाइल है:

#[no_mangle] 
pub extern fn my_func(x: i32, y: i32) -> i32 { 
    return x + y; 
} 

मैं इस प्रकार है के रूप में उपयोग कर सकते हैं:

In [1]: from ctypes import cdll 

In [2]: lib = cdll.LoadLibrary("/home/user/RustStuff/embed/target/release/libembed.so") 

In [3]: lib.my_func(5,6) 
Out[3]: 11 

लेकिन अगर मैं बदल मेरी lib.rs रहे हैं:

#[no_mangle] 
pub extern fn my_func(my_vec: Vec<i32>) -> i32 { 
    let mut my_sum = 0; 
    for i in my_vec { 
     my_sum += i; 
    } 
    return my_sum; 
} 

मैं अब कर सकते हैं इसे पायथन में उपयोग करें (यह संकलित ठीक है):

In [1]: from ctypes import cdll 

In [2]: lib = cdll.LoadLibrary("/home/user/RustStuff/embed/target/release/libembed.so") 

In [3]: lib.my_func([2,3,4]) 
--------------------------------------------------------------------------- 
ArgumentError        Traceback (most recent call last) 
<ipython-input-3-454ffc5ba9dd> in <module>() 
----> 1 lib.my_func([2,3,4]) 

ArgumentError: argument 1: <type 'exceptions.TypeError'>: Don't know how to convert parameter 1 

कारण, मैं

क्यों मेरी प्रयास काम नहीं करता है, हालांकि यह काम कर सकता है कि अजगर के list और जंग के Vec दोनों गतिशील सरणियों, लेकिन जाहिरा तौर पर मैं कुछ यहाँ याद आ रही है ...? इसे ठीक करने के लिए मुझे क्या करना चाहिए?

उत्तर

13

डॉन 'होगा टी ऐसा करें:

#[no_mangle] 
pub extern fn my_func(my_vec: Vec<i32>) -> i32 { ... } 

आप मूल रूप से कभी नहीं स्वीकार करते हैं या एक extern समारोह में एक मनमाना जंग वस्तु वापस जाने के लिए, केवल जो कि Repr हैं चाहता हूँ। इसके बजाय, आपको कुछ ऐसा स्वीकार करना चाहिए जो सी द्वारा दर्शाया जा सके। 6502 says के रूप में, इस विशेष मामले के लिए सबसे अच्छा विचार एक सूचक और लंबाई स्वीकार करना होगा।

जंग का Vec संकल्पनात्मक रूप से डेटा, एक गिनती, और एक क्षमता पर सूचक है। आप वस्तुओं को जोड़ने या हटाने के द्वारा Vec को संशोधित करने में सक्षम हैं, जो पुनर्वितरण होने का कारण बन सकता है।यह दोगुना खराब है क्योंकि यह संभव है कि पायथन और जंग विभिन्न आवंटकों का उपयोग करें जो एक दूसरे के साथ संगत नहीं हैं। Segfaults इस तरह झूठ बोलते हैं! आप वास्तव में टुकड़ा चाहते हैं।

इसके बजाय, जंग पक्ष पर कुछ इस तरह करते हैं:

extern crate libc; 

use libc::{size_t,int32_t}; 
use std::slice; 

#[no_mangle] 
pub extern fn my_func(data: *const int32_t, length: size_t) -> int32_t { 
    let nums = unsafe { slice::from_raw_parts(data, length as usize) }; 
    nums.iter().fold(0, |acc, i| acc + i) 
} 

अर्थात्, आप की गारंटी करने के लिए मैच सी प्रकार का उपयोग कर रहे हैं, और फिर कुछ करने के लिए सूचक और लंबाई जंग जानता है परिवर्तित करने के लिए कैसे निपटने के लिए साथ में।

मुझे कोई Pythonista हूँ, लेकिन यह जोड़-तोड़ कर कोड (How do I convert a Python list into a C array by using ctypes? की मदद से) जंग के साथ काम करने लगता है मैं ऊपर है:

import ctypes 

lib = ctypes.cdll.LoadLibrary("./target/debug/libpython.dylib") 
lib.my_func.argtypes = (ctypes.POINTER(ctypes.c_int32), ctypes.c_size_t) 

list_to_sum = [1,2,3,4] 
c_array = (ctypes.c_int32 * len(list_to_sum))(*list_to_sum) 
print lib.my_func(c_array, len(list_to_sum)) 
बेशक

, तो आप शायद रैप करने के लिए है कि बनाना चाहते यह आपके कोड के कॉलर के लिए अच्छा है।

5

ctypes सी बाइंडिंग के बारे में है और सी में गतिशील सरणी जैसी कोई चीज़ नहीं है।

निकटतम वस्तु आप एक सी कार्य करने के लिए पारित कर सकते हैं कि हालांकि पूर्णांक एक सूचक है एक गतिशील सरणी क्योंकि

  1. यह या आकार जानकारी
  2. आप विकसित नहीं कर सकते हैं नहीं होता हटना नहीं है क्षेत्र, मौजूदा तत्वों का उपयोग करें

पॉइंटर्स पास करने के लिए एक साधारण विकल्प (और आकार के पीछे नहीं होने के बारे में बहुत सावधान रहना) आप इसका उपयोग कर सकते हैं बजाय फ़ंक्शन-आधारित API है।

उदाहरण के लिए

:

getNumberOfThings() -> number 
getThing(index) -> thing 

लेकिन अजगर कोड तो जैसे

def func(): 
    n = getNumberOfThings() 
    return [getThing(i) for i in range(n)] 

बन जाएगा समकक्ष (तत्वों के परिवर्तनशील गुजर)

def func2(L): 
    setNumberOfThings(len(L)) 
    for i, x in enumerate(L): 
     setThing(i, x)