एक स्ट्रीम अडैप्टर लिखिए जिसमें किसी कुंजी का रेफरेंस हो, और जो उस कुंजी का बिटवाइज़ XOR किसी भी डेटा के साथ करे।
XOR एक बुनियादी बाइनरी ऑपरेशन है: इनपुट के हर बिट के लिए, अगर इनपुट बिट अलग-अलग हैं तो आउटपुट के उससे जुड़े बिट को 1 पर सेट कीजिए। अगर दोनों इनपुट 1 हैं या दोनों 0 हैं, तो आउटपुट का वह बिट 0 होता है।
किसी दस्तावेज़ का किसी कुंजी के साथ XOR करते समय कुंजी को जितनी बार ज़रूरी हो उतनी बार दोहराया जाता है। इससे एक ऐसा आउटपुट दस्तावेज़ बनता है जिसकी लंबाई इनपुट दस्तावेज़ के बराबर होती है।
किसी दस्तावेज़ का किसी कुंजी के साथ XOR करना 1900 के दशक की शुरुआत तक भी क्रिप्टोग्राफी में इस्तेमाल होता रहा है। डेटा छिपाने के तरीके के रूप में यह अब पूरी तरह पुराना पड़ चुका है, फिर भी बिना असली रैंडमनेस की उलझन के शोर भरा, रैंडम जैसा दिखने वाला डेटा बनाने के लिए यह आश्चर्यजनक रूप से उपयोगी हो सकता है। आधुनिक क्रिप्टोग्राफी में कुछ साइफरों के लिए इसका इस्तेमाल आज भी कभी-कभी होता है: साइफर खुद तो बस एक ऐसा तरीका है जो बहुत रैंडम, अनंत लंबाई वाली कुंजी बनाता है, और उसी कुंजी का XOR दस्तावेज़ के साथ किया जाता है।
XOR एन्क्रिप्शन की एक दिलचस्प विशेषता यह है कि यह सममित है: किसी भी संख्या का XOR उसी संख्या के साथ 0 देता है, और किसी भी संख्या का XOR 0 के साथ करने पर वही संख्या बिना बदलाव के वापस मिलती है। इसलिए, XOR से एन्क्रिप्ट किए गए दस्तावेज़ को डिक्रिप्ट करने के लिए उसे उसी कुंजी से दोबारा XOR-एन्क्रिप्ट कीजिए।
यह जाँचने के लिए कोई टेस्ट लिखना व्यावहारिक नहीं है कि आपके स्ट्रक्ट में कुंजी को कॉपी करने के बजाय उसका रेफरेंस रखा गया है। इसी तरह, यह साबित करना भी किसी टेस्ट से व्यावहारिक नहीं है कि न munge और न munge_in_place, और न ही उनके कोई हेल्पर फंक्शन, हीप पर एलोकेशन करते हैं। फिर भी, आपको अपना हल इसी तरह लिखने की कोशिश करनी चाहिए।
आपको एक struct Xorcism लिखना होगा जिसमें किसी कुंजी का रेफरेंस हो। उस स्ट्रक्ट में दो मेथड देने होंगे: munge_in_place और munge। पहला एक बाइट बफ़र को उसी जगह पर बदल देता है। दूसरा एक इटरेटर अडैप्टर है: यह डेटा का कोई भी इटरेटर लेता है और डेटा का एक नया इटरेटर लौटाता है।
इस अभ्यास के स्टब सिग्नेचर सिंटैक्स की दृष्टि से काफी हद तक सही हैं, लेकिन वे कंपाइल नहीं होते: इस अभ्यास का बड़ा उद्देश्य यही है कि आप लाइफटाइम और जेनेरिक्स के इस्तेमाल से परिचित हों, इसलिए आपको इन्हें खुद भरना होगा। इस अभ्यास का एक और लक्ष्य यह है कि आप एक उपयुक्त फैक्टराइज़ेशन निकालें, जिससे आप उन दोनों मेथड को बहुत कम दोहराव के साथ लागू कर सकें। अतिरिक्त हेल्पर जोड़ने से मत डरिए!
ये ट्रेट उपयोगी होंगे:
इस अभ्यास में कुछ बोनस टेस्ट हैं, जो io फीचर फ्लैग के पीछे हैं। इन्हें चालू करने के लिए यह चलाइए
cargo test --features io
इन टेस्टों के लिए, आपको यह सिग्नेचर वाला एक मेथड reader लागू करना होगा
fn reader(self, impl Read) -> impl Read
और यह सिग्नेचर वाला एक मेथड writer
fn writer(self, impl Write) -> impl Write
ये फंक्शन Xorcism स्ट्रक्ट को सही दिशा में एक स्ट्रीम अडैप्टर में बदल देते हैं। ये इन ट्रेट का इस्तेमाल करते हैं:
munge की रिटर्न वैल्यू का लाइफटाइमimpl Trait फीचर के उपयोग के कारण munge मेथड लागू करते समय लाइफटाइम का प्रबंधन थोड़ा मुश्किल हो सकता है। शुरुआत करने के लिए आप अपना खुद का struct लिखकर उसमें Iterator लागू कर सकते हैं और उस ठोस टाइप को लौटा सकते हैं। अंत में, सीधे Iterator कॉम्बिनेटर इस्तेमाल करके हल लिखने की कोशिश करना अच्छा रहता है।