// Opaque types: the type's representation is hidden from callers.
// Only the declared interface is accessible; the concrete implementation
// cannot be inspected or constructed directly.
//
// Rust achieves this via:
// - Structs with private fields (module-level privacy)
// - `impl Trait` return types (opaque impl in function signatures)
// - Sealed traits (callers can use but not implement — see 148)
// ── Stack with private representation ────────────────────────────────────────
pub mod stack {
/// An opaque LIFO stack. Callers see only `Stack<T>`, not its internals.
#[derive(Debug, Clone)]
pub struct Stack<T>(Vec<T>); // inner Vec is private
impl<T> Stack<T> {
pub fn empty() -> Self {
Stack(Vec::new())
}
pub fn push(mut self, x: T) -> Self {
self.0.push(x);
self
}
pub fn pop(mut self) -> (Option<T>, Self) {
let top = self.0.pop();
(top, self)
}
pub fn peek(&self) -> Option<&T> {
self.0.last()
}
pub fn size(&self) -> usize {
self.0.len()
}
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
}
}
// ── Queue with private representation ────────────────────────────────────────
pub mod queue {
/// A FIFO queue backed by two stacks (amortised O(1) enqueue/dequeue).
#[derive(Debug, Clone)]
pub struct Queue<T> {
inbox: Vec<T>,
outbox: Vec<T>,
}
impl<T> Queue<T> {
pub fn empty() -> Self {
Queue { inbox: Vec::new(), outbox: Vec::new() }
}
pub fn enqueue(mut self, x: T) -> Self {
self.inbox.push(x);
self
}
pub fn dequeue(mut self) -> (Option<T>, Self) {
if self.outbox.is_empty() {
while let Some(x) = self.inbox.pop() {
self.outbox.push(x);
}
}
let item = self.outbox.pop();
(item, self)
}
pub fn peek(&mut self) -> Option<&T> {
if self.outbox.is_empty() {
while let Some(x) = self.inbox.pop() {
self.outbox.push(x);
}
}
self.outbox.last()
}
pub fn size(&self) -> usize {
self.inbox.len() + self.outbox.len()
}
pub fn is_empty(&self) -> bool {
self.inbox.is_empty() && self.outbox.is_empty()
}
}
}
// ── `impl Trait` opaque return types ─────────────────────────────────────────
// The caller sees `impl Iterator<Item = i32>` but not the concrete type.
fn make_counter(start: i32, step: i32) -> impl Iterator<Item = i32> {
// Could be any iterator internally; caller cannot name the type.
(0..).map(move |i| start + i * step)
}
fn make_even_squares() -> impl Iterator<Item = u64> {
(1u64..).map(|n| n * n).filter(|n| n % 2 == 0)
}
/// A secret key type — callers can't construct one directly.
pub struct SecretKey(Vec<u8>);
impl SecretKey {
/// Only way to get a SecretKey: go through this validated constructor.
pub fn new(key: &[u8]) -> Result<Self, &'static str> {
if key.len() >= 16 {
Ok(SecretKey(key.to_vec()))
} else {
Err("key must be at least 16 bytes")
}
}
pub fn len(&self) -> usize {
self.0.len()
}
pub fn xor_encrypt(&self, data: &[u8]) -> Vec<u8> {
data.iter()
.zip(self.0.iter().cycle())
.map(|(d, k)| d ^ k)
.collect()
}
}
fn main() {
use stack::Stack;
use queue::Queue;
// ── Stack ─────────────────────────────────────────────────────────────────
let s = Stack::empty()
.push(1)
.push(2)
.push(3);
println!("size: {}", s.size());
println!("peek: {:?}", s.peek());
let (top, rest) = s.pop();
println!("popped: {:?}, new size: {}", top, rest.size());
println!("empty: {}", Stack::<i32>::empty().is_empty());
// ── Queue ─────────────────────────────────────────────────────────────────
let q = Queue::empty()
.enqueue("first")
.enqueue("second")
.enqueue("third");
println!("\nQueue size: {}", q.size());
let (item, q2) = q.dequeue();
println!("dequeued: {:?}", item);
println!("remaining: {}", q2.size());
// ── impl Trait opaque returns ─────────────────────────────────────────────
let counter: Vec<i32> = make_counter(10, 5).take(4).collect();
println!("\ncounter(10, step=5): {:?}", counter);
let squares: Vec<u64> = make_even_squares().take(5).collect();
println!("first 5 even squares: {:?}", squares);
// ── Validated opaque SecretKey ────────────────────────────────────────────
match SecretKey::new(b"this-is-a-valid-key-32-bytes-long!") {
Ok(key) => {
println!("\nkey len: {}", key.len());
let ct = key.xor_encrypt(b"hello");
let pt = key.xor_encrypt(&ct);
println!("xor round-trip: {:?}", std::str::from_utf8(&pt).unwrap());
}
Err(e) => println!("Key error: {}", e),
}
println!("short key: {:?}", SecretKey::new(b"short").err());
}
#[cfg(test)]
mod tests {
use super::stack::Stack;
use super::queue::Queue;
use super::{SecretKey, make_counter};
#[test]
fn test_stack_push_pop() {
let s = Stack::empty().push(10).push(20).push(30);
assert_eq!(s.size(), 3);
let (top, rest) = s.pop();
assert_eq!(top, Some(30));
assert_eq!(rest.size(), 2);
}
#[test]
fn test_stack_empty() {
let s = Stack::<i32>::empty();
assert!(s.is_empty());
let (top, _) = s.pop();
assert_eq!(top, None);
}
#[test]
fn test_queue_fifo() {
let q = Queue::empty().enqueue(1).enqueue(2).enqueue(3);
let (a, q) = q.dequeue();
let (b, q) = q.dequeue();
let (c, _) = q.dequeue();
assert_eq!((a, b, c), (Some(1), Some(2), Some(3)));
}
#[test]
fn test_impl_trait_counter() {
let v: Vec<i32> = make_counter(0, 2).take(5).collect();
assert_eq!(v, vec![0, 2, 4, 6, 8]);
}
#[test]
fn test_secret_key_validation() {
assert!(SecretKey::new(b"this-is-16-bytes").is_ok());
assert!(SecretKey::new(b"short").is_err());
}
#[test]
fn test_xor_encrypt_decrypt() {
let key = SecretKey::new(b"sixteen-byte-key").unwrap();
let data = b"hello world";
let encrypted = key.xor_encrypt(data);
let decrypted = key.xor_encrypt(&encrypted);
assert_eq!(decrypted, data);
}
}
(* Opaque types: the type's representation is hidden by the module signature.
Callers can only use the type through the provided interface. *)
module type STACK = sig
type 'a t
val empty : 'a t
val push : 'a -> 'a t -> 'a t
val pop : 'a t -> ('a * 'a t) option
val peek : 'a t -> 'a option
val size : 'a t -> int
val is_empty : 'a t -> bool
end
(* List-based implementation — type is opaque outside this module *)
module Stack : STACK = struct
type 'a t = 'a list
let empty = []
let push x s = x :: s
let pop = function
| [] -> None
| x :: xs -> Some (x, xs)
let peek = function
| [] -> None
| x :: _ -> Some x
let size = List.length
let is_empty = (= [])
end
let () =
let s = Stack.(push 3 (push 2 (push 1 empty))) in
Printf.printf "size: %d\n" (Stack.size s);
Printf.printf "peek: %d\n" (Option.get (Stack.peek s));
(match Stack.pop s with
| Some (top, rest) ->
Printf.printf "popped: %d, new size: %d\n" top (Stack.size rest)
| None -> assert false);
Printf.printf "empty: %b\n" (Stack.is_empty Stack.empty)