2015-01-24 23 views
8

मैं अपनी संरचना TcpStream के माध्यम से भेजना चाहता हूं। मैं String या u8 भेज सकता था, लेकिन मैं एक मनमानी संरचना नहीं भेज सकता। उदाहरण के लिए:'struct' से '& [u8]' को कैसे परिवर्तित करें?

struct MyStruct { 
    id: u8, 
    data: [u8; 1024], 
} 

let my_struct = MyStruct { id: 0, data: [1; 1024] }; 
let bytes: &[u8] = convert_struct(my_struct); // how?? 
tcp_stream.write(bytes); 

डेटा प्राप्त करने के बाद, मैं &[u8]MyStruct वापस करने के लिए परिवर्तित करना चाहते हैं। मैं इन दो प्रतिनिधियों के बीच कैसे परिवर्तित कर सकता हूं?

मुझे पता है कि जंग को डेटा को क्रमबद्ध करने के लिए एक JSON मॉड्यूल है, लेकिन मैं JSON का उपयोग नहीं करना चाहता क्योंकि मैं जितना संभव हो सके डेटा को तेज़ और छोटा भेजना चाहता हूं, इसलिए मैं कोई छोटा या छोटा नहीं चाहता हूं।

उत्तर

9

शायद bincode की तरह एक समाधान अपने मामले के अनुरूप होगा (बेशर्मी एक समान प्रश्न पर Renato Zannon's comment से चोरी हो)?

Cargo.toml

[package] 
name = "foo" 
version = "0.1.0" 
authors = ["An Devloper <[email protected]>"] 

[dependencies] 
bincode = "0.6.1" 
serde_derive = "0.8.23" 

main.rs

extern crate bincode; 
#[macro_use] 
extern crate serde_derive; 

use std::fs::File; 

#[derive(Serialize, Deserialize)] 
struct A { 
    id: i8, 
    key: i16, 
    name: String, 
    values: Vec<String>, 
} 

fn main() { 
    let a = A { 
     id: 42, 
     key: 1337, 
     name: "Hello world".to_string(), 
     values: vec!["alpha".to_string(), "beta".to_string()], 
    }; 

    // Encode to something implementing Write 
    let mut f = File::create("/tmp/output.bin").unwrap(); 
    bincode::serde::serialize_into(&mut f, &a, bincode::SizeLimit::Infinite).unwrap(); 

    // Or just to a buffer 
    let bytes = bincode::serde::serialize(&a, bincode::SizeLimit::Infinite).unwrap(); 
    println!("{:?}", bytes); 
} 

फिर आप बाइट्स भी आप चाहते हैं भेजने के लिए सक्षम हो जाएगा: यहाँ एक काम अंश है। मुझे लगता है कि आप पहले से ही निष्क्रिय रूप से बाइट्स भेजने (जैसे संभावित अंतहीनता मुद्दों या संस्करण) के मुद्दों के बारे में जानते हैं, लेकिन मैं उन्हें^^^के मामले में उल्लेख करूंगा।

+0

यह मेरे मामले में उपयोगी प्रतीत होता है !! उत्तर देने के लिए आपका शुक्रिया! – agatana

+0

यह ध्यान देने योग्य है कि यह प्रत्यक्ष रूपांतरण नहीं है, जबकि एन्कोडिंग/डिकोडिंग एक द्विआधारी प्रारूप का उपयोग करता है, यह केवल उस सामग्री के आधार पर संरचना की स्मृति (जिसे एक अच्छी और बुरी चीज दोनों के रूप में देखा जा सकता है) तक पहुंच नहीं है, यह कुछ रूपांतरण कर रहा है। उदाहरण के लिए बिनकोड भी एंडियन रूपांतरण करता है। – ideasman42

9

शून्य-प्रतिलिपि बाइट्स के रूप में सही ढंग से आकार की संरचना stdlib और एक सामान्य कार्य का उपयोग करके किया जा सकता है।

नीचे दिए गए उदाहरण में नामक एक पुन: प्रयोज्य फ़ंक्शन है जो convert_struct के बजाय है, क्योंकि यह कास्ट और स्लाइस निर्माण को लपेटने के लिए उपयोगिता है।

ध्यान दें कि प्रश्न परिवर्तित करने के बारे में पूछता है, यह उदाहरण केवल पढ़ने के लिए टुकड़ा बनाता है, इसलिए स्मृति की प्रतिलिपि बनाने की आवश्यकता नहीं है।

उसके बारे में यहां काम कर प्रश्न के आधार पर उदाहरण:

unsafe fn any_as_u8_slice<T: Sized>(p: &T) -> &[u8] { 
    ::std::slice::from_raw_parts(
     (p as *const T) as *const u8, 
     ::std::mem::size_of::<T>(), 
    ) 
} 

fn main() { 
    struct MyStruct { 
     id: u8, 
     data: [u8; 1024], 
    } 
    let my_struct = MyStruct { id: 0, data: [1; 1024] }; 
    let bytes: &[u8] = unsafe { any_as_u8_slice(&my_struct) }; 
    // tcp_stream.write(bytes); 
    println!("{:?}", bytes); 
} 

नोट 1) भले ही 3 पार्टी क्रेट कुछ मामलों में बेहतर हो सकता है, इस तरह के एक आदिम आपरेशन कि करने के लिए अपने उपयोगी है जंग में कैसे करना है पता है।

नोट 2) लेखन के समय (जंग 1.15), const कार्यों के लिए कोई समर्थन नहीं है। एक बार वहां, एक स्लाइस के बजाय एक निश्चित आकार के सरणी में डालना संभव होगा।

नोट 3)any_as_u8_slice समारोह unsafe चिह्नित क्योंकि struct में किसी भी पैडिंग बाइट्स स्मृति (अपरिभाषित व्यवहार दे रही है) अप्रारंभीकृत किया जा सकता है। यदि इनपुट तर्क सुनिश्चित करने का कोई तरीका था तो केवल structs का उपयोग किया गया था जो #[repr(packed)] थे, तो यह सुरक्षित हो सकता है।

अन्यथा फ़ंक्शन काफी सुरक्षित है क्योंकि यह बफर ओवर-रन को रोकता है क्योंकि आउटपुट केवल पढ़ने के लिए, बाइट्स की निश्चित संख्या है, और इसका जीवनकाल इनपुट से जुड़ा हुआ है।
यदि आप एक संस्करण चाहते थे जो &mut [u8] लौटा, तो यह काफी खतरनाक होगा क्योंकि संशोधित आसानी से असंगत/भ्रष्ट डेटा बना सकता है।

संबंधित मुद्दे