From 4a71624acc8fa28401f41d70cd6bb5bb7e5bb378 Mon Sep 17 00:00:00 2001 From: Mariano Riefolo Date: Tue, 13 Aug 2024 14:26:33 +0200 Subject: [PATCH] Wrote program for Day 19 --- README.md | 2 +- Week-03/Day-19_URL-Shortener/day19/Cargo.toml | 6 ++ Week-03/Day-19_URL-Shortener/day19/src/lib.rs | 98 +++++++++++++++++++ .../Day-19_URL-Shortener/day19/src/main.rs | 45 +++++++++ 4 files changed, 150 insertions(+), 1 deletion(-) create mode 100644 Week-03/Day-19_URL-Shortener/day19/Cargo.toml create mode 100644 Week-03/Day-19_URL-Shortener/day19/src/lib.rs create mode 100644 Week-03/Day-19_URL-Shortener/day19/src/main.rs diff --git a/README.md b/README.md index 0271d10..0c190c4 100644 --- a/README.md +++ b/README.md @@ -65,7 +65,7 @@ We encourage you to share your progress and ask questions in the Discussions sec | Day #16 | [Nim Game](https://github.com/LiveGray/100-Days-Of-Rust/tree/main/Week-03/Day-16_Nim-Game) | :white_check_mark: | | Day #17 | [Prison Break](https://github.com/LiveGray/100-Days-Of-Rust/tree/main/Week-03/Day-17_Prison-Break) | :white_check_mark: | | Day #18 | [Unique Paths](https://github.com/LiveGray/100-Days-Of-Rust/tree/main/Week-03/Day-18_Unique-Paths) | :white_check_mark: | -| Day #19 | [URL Shortener](https://github.com/LiveGray/100-Days-Of-Rust/tree/main/Week-03/Day-19_URL-Shortener) | :white_large_square: | +| Day #19 | [URL Shortener](https://github.com/LiveGray/100-Days-Of-Rust/tree/main/Week-03/Day-19_URL-Shortener) | :white_check_mark: | | Day #20 | [API Challenge](https://github.com/LiveGray/100-Days-Of-Rust/tree/main/Week-03/Day-20_API-Challenge) | :white_large_square: | | Day #21 | [Random Maze Generator](https://github.com/LiveGray/100-Days-Of-Rust/tree/main/Week-03/Day-21_Random-Maze-Generator) | :white_large_square: | | Day #22 | [Marcio Mellos Challenge](https://github.com/LiveGray/100-Days-Of-Rust/tree/main/Week-04/Day-22_Marcio-Mellos-Challenge) | :white_large_square: | diff --git a/Week-03/Day-19_URL-Shortener/day19/Cargo.toml b/Week-03/Day-19_URL-Shortener/day19/Cargo.toml new file mode 100644 index 0000000..27216fa --- /dev/null +++ b/Week-03/Day-19_URL-Shortener/day19/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "day19" +version = "0.1.0" +edition = "2021" + +[dependencies] diff --git a/Week-03/Day-19_URL-Shortener/day19/src/lib.rs b/Week-03/Day-19_URL-Shortener/day19/src/lib.rs new file mode 100644 index 0000000..804d766 --- /dev/null +++ b/Week-03/Day-19_URL-Shortener/day19/src/lib.rs @@ -0,0 +1,98 @@ +use std::time::{SystemTime, UNIX_EPOCH}; + +fn valid_url(url: &str) -> Result<(), &str> { + if !url.starts_with("http://") && !url.starts_with("https://") { + Err("URL should start with either http:// or https://") + } else if url.contains(' ') { + Err("URL should not contain spaces") + } else if url.len() < 12 { + Err("URL should be at least 12 characters long") + } else if url.len() > 2048 { + Err("URL should not be longer than 2048 characters") + } else if url.contains('\n') { + Err("URL should not contain newlines") + } else { + Ok(()) + } +} + +pub fn url_shortener(url: &str, custom: Option, rng: Option) -> Result { + valid_url(url)?; + + let domain = "https://shortener.rs/"; + + if let Some(custom) = custom { + Ok(format!("{}{}", domain, custom)) + } else if let Some(mut rng) = rng { + Ok(format!("{}{}", domain, rng.random_string())) + } else { + Err("Either custom or rng should be provided") + } +} + +pub struct Rng { + seed: u128, +} + +impl Rng { + pub fn new() -> Rng { + let time_since_epoch = SystemTime::now() + .duration_since(UNIX_EPOCH) + .expect("Error in getting time") + .as_millis(); + Rng { + seed: time_since_epoch, + } + } + + pub fn random_string(&mut self) -> String { + let random_number = self.linear_congruent_generator(1103515245, 12345, 2u128.pow(31)); + let binding = random_number.to_string(); + let bytes = binding.as_bytes(); + let (bytes, padding) = Rng::split_bits(bytes); + let alphabet = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".as_bytes(); + let mut result = String::new(); + for b in bytes { + result.push(alphabet[b as usize] as char); + } + for _ in (0..padding).step_by(2) { + result.push('='); + } + result + } + + fn split_bits(bytes: &[u8]) -> (Vec, usize) { + let mut bits = Vec::new(); + for &byte in bytes { + for i in (0..8).rev() { + bits.push((byte >> i) & 1); + } + } + let mut result = Vec::new(); + let mut padding = 0; + for chunk in bits.chunks(6) { + let mut byte = 0; + for (i, &bit) in chunk.iter().enumerate() { + byte |= bit << (5 - i); + } + result.push(byte); + if chunk.len() < 6 { + padding = 6 - chunk.len(); + } + } + (result, padding) + } + + fn linear_congruent_generator(&mut self, a: u128, c: u128, m: u128) -> u128 { + let result = (a * self.seed + c) % m; + self.seed = result; + result + } +} + +impl Default for Rng { + fn default() -> Self { + Self::new() + } +} diff --git a/Week-03/Day-19_URL-Shortener/day19/src/main.rs b/Week-03/Day-19_URL-Shortener/day19/src/main.rs new file mode 100644 index 0000000..5a65fa2 --- /dev/null +++ b/Week-03/Day-19_URL-Shortener/day19/src/main.rs @@ -0,0 +1,45 @@ +use day19::{url_shortener, Rng}; +use std::io::{self, Write}; + +fn main() { + let rng = Rng::new(); + let mut buffer = String::new(); + + print!("Enter the URL to shorten: "); + io::stdout().flush().expect("Failed to flush stdout"); + + io::stdin() + .read_line(&mut buffer) + .expect("Failed to read from stdin"); + + let url = buffer.trim().to_owned(); + buffer = String::new(); + + print!("Do you want to provide a custom short URL? (y/n): "); + io::stdout().flush().expect("Failed to flush stdout"); + + io::stdin() + .read_line(&mut buffer) + .expect("Failed to read from stdin"); + + let short_url = if buffer.trim() == "y" { + buffer = String::new(); + + print!("Enter the custom short URL: "); + io::stdout().flush().expect("Failed to flush stdout"); + + io::stdin() + .read_line(&mut buffer) + .expect("Failed to read from stdin"); + + let custom = Some(buffer.trim().to_string()); + url_shortener(&url, custom, None) + } else { + url_shortener(&url, None, Some(rng)) + }; + + match short_url { + Ok(short_url) => println!("Shortened URL: {}", short_url), + Err(e) => eprintln!("Error: {}", e), + } +}