এমন একটি স্ট্রিমিং অ্যাডাপ্টর লিখুন, যেটি একটি কী-এর রেফারেন্স ধরে রাখে এবং যেকোনো ডেটার সঙ্গে সেটি বিটভিত্তিক XOR করে।
XOR একটি মৌলিক বাইনারি অপারেশন: ইনপুটের প্রতিটি বিটের জন্য, ইনপুট বিটগুলো ভিন্ন হলে আউটপুটের সংশ্লিষ্ট বিটটি 1 করুন। ইনপুট দুটোই 1 হলে বা দুটোই 0 হলে, সংশ্লিষ্ট আউটপুট বিটটি 0 হয়।
একটি ডকুমেন্টের সঙ্গে একটি কী XOR করার সময়, প্রয়োজন অনুযায়ী কীটি যতবার দরকার ততবার পুনরাবৃত্তি করা হয়, আর এভাবে ইনপুট ডকুমেন্টের সমান দৈর্ঘ্যের একটি আউটপুট ডকুমেন্ট তৈরি হয়।
কী দিয়ে একটি ডকুমেন্ট XOR করা ঊনিশশো শতকের গোড়ার দিক পর্যন্ত ক্রিপ্টোগ্রাফিতে ব্যবহৃত হয়েছে। ডেটা লুকানোর পদ্ধতি হিসেবে এটি পুরোপুরি অচল হলেও, সত্যিকারের র্যান্ডমনেসের জটিলতা ছাড়াই এলোমেলো-দেখতে শব্দময় ডেটা তৈরি করার জন্য এটি অবাক করার মতোই কাজে আসতে পারে। আধুনিক ক্রিপ্টোগ্রাফিতেও কিছু নির্দিষ্ট সাইফারে এটি মাঝেমধ্যে ব্যবহৃত হয়: সাইফারটি আসলে খুব র্যান্ডম, অসীম দীর্ঘ একটি কী তৈরির কৌশল মাত্র, যা দিয়ে ডকুমেন্ট XOR করা হয়।
XOR এনক্রিপশনের একটি মজার বৈশিষ্ট্য হলো এটি প্রতিসম: যেকোনো সংখ্যাকে তার নিজের সঙ্গে XOR করলে 0 পাওয়া যায়, আর যেকোনো সংখ্যাকে 0-এর সঙ্গে XOR করলে ইনপুট সংখ্যাটিই অপরিবর্তিত থাকে। তাই 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 কম্বিনেটর দিয়ে সমাধানটি ইমপ্লিমেন্ট করার চেষ্টা করে দেখাই ভালো।
Exercism-এ সাইন আপ করুন, Rust ট্র্যাকের 99টি অনুশীলনী আর সত্যিকারের মানুষের মেন্টরিং দিয়ে শিখুন ও দক্ষ হয়ে উঠুন, সম্পূর্ণ বিনামূল্যে।