New blogpost! (and some updates)

This commit is contained in:
CherryKitten 2023-02-23 17:33:46 +01:00
parent 19aa58e531
commit 7ee9e8cb8e
Signed by: sammy
GPG key ID: 0B696A86A853E955
37 changed files with 776 additions and 48 deletions

View file

@ -39,7 +39,12 @@ background_color = "rosepine"
logo_text = "CherryKitten"
copyright_html = """\
<p>&copy; {currentYear} - CherryKitten</p><a href="/impressum">Impressum</a>
<p>&copy; 2023 - CherryKitten</p><br>
<p><a href="/impressum">Impressum</a></p>
 
<p><a href="/rss.xml">RSS</a></p>
 
🐱
"""
menu_items = [
@ -53,3 +58,4 @@ menu_items = [
]
page_titles = "combined"
post_view_navigation_prompt = "More posts!"

View file

@ -0,0 +1,245 @@
+++
title = "Learning Rust Part 1: A kitten's guide to Options and Results"
date = 2023-02-25
[taxonomies]
tags=["Rust", "programming", "code", "learning"]
+++
### To unwrap() or not to unwrap(), that is the question:
So I've finally given in and started to learn Rust last month. It's a really cool programming language,
with some interesting differences to what I've used before. (JavaScript and Python, mostly)
There are some really pawesome guides out there, ["The Rust programming language"](https://doc.rust-lang.org/book/) is
definitely a **must-read** in my opinion, and [Rustlings](https://github.com/rust-lang/rustlings) is nyamazing for
anyone who likes to learn by actively working through interactive problems.
After reading through a lot of those big thorough guides by experienced Rust developers, I've started working on
my first actual Project. I approached the development of this project by just trying to get small parts of it
working in any way I can manage, and then build upon this. In that process, I learned a lot of small subtilties that
guides like the ones named above just can't really cover. This post is for sharing those things, those cool little
tips to make your first Rust project just a little cleaner and more Rust-y. Originally I wanted to make this about a lot
of different topics, but then I've realized that my notes already contain so many things about just one part of Rust:
The Enums `Option` and `Result`. So this post will be about those, and hopefully will mark the start of a series on this blog.
While reading through this, you might think that the things I'm mentioning are obvious. That's okay, and that's the point.
Nothing is ever completely obvious to everyone, and this is for those like me, who often don't immediately recognize
the "obvious". And, to be honest, I am writing this just as much for myself, writing all of that stuff down to aid me in my
own ongoing learning process.
So, let's start!
<!-- more -->
Firstly, a very quick introduction. `Option` and `Result` are part of the Rust standard library. Quoting the official documentation
is probably the easiest way to summarize their purpose:
> Type `Option` represents an optional value: every Option is either `Some` and contains a value, or `None`, and does not. `Option` types are very common in Rust code, as they have a number of uses:
>
> * Initial values
> * Return values for functions that are not defined over their entire input range (partial functions)
> * Return value for otherwise reporting simple errors, where `None` is returned on error
> * Optional struct fields
> * Struct fields that can be loaned or “taken”
> * Optional function arguments
> * Nullable pointers
> * Swapping things out of difficult situations
and
> `Result<T, E>` is the type used for returning and propagating errors. It is an enum with the variants, `Ok(T)`, representing success and containing a value, and `Err(E)`, representing error and containing an error value.
At first, it seems so easy to just add a quick `.unwrap()` after every `Option` or `Result`, but this comes with
the disadvantage of your code [panicking](https://doc.rust-lang.org/std/macro.panic.html) if it fails to unwrap.
Sometimes, this can be useful during development, to discover potential error cases you might not have thought about, but
is usually not what you want to happen.
So, what can you do instead?
First of all, don't use `unwrap()` unless you are completely sure that the value will never panic. Sometimes that is the
case, because an earlier part of your code already made sure that it is `Ok` or `Some`.
In some cases, you actually want the program to panic. But even then, there is a slightly better way. You can use `expect("foo")`
to add a message to the panic, so the user actually knows what went wrong. That message should be worded in a specific way,
basically telling the user what you _expected_ to happen.
```rust
fn main() {
let x = Some("Hello, World");
// There is no actual "None" type/value in Rust,
// this "None" is more specifically Option::None
let y: Option<String> = None;
let z = x.unwrap(); // We explicitly set this to Some, so we can safely unwrap it
let rip = y.expect("expected y to not be None");
println!("{}, {} will never print because it panics above", z, rip);
}
```
There are also the non-panicking siblings of `unwrap()`, like `unwrap_or()`, `unwrap_or_else()` and `unwrap_or_default()`.
```rust
fn main() {
let a: Option<String> = None;
let b: Option<i32> = None;
let c: Option<bool> = None;
// unwrap_or() lets you supply a specific value to use if the Option is None
let x = a.unwrap_or("Hello there".to_owned());
// unwrap_or_default() uses the types default value if the Option is None
let y = b.unwrap_or_default();
// unwrap_or_else() lets you specify a closure to run if the Option is None
let z = c.unwrap_or_else(|| if 1 + 1 == 2 { true} else { false });
assert_eq!(x, "Hello there".to_owned());
assert_eq!(y, 0);
assert_eq!(z, true);
}
```
And then there is this really cool question-mark operator, which comes in very handy once you go multiple functions deep
and keep having to work with more and more `Result`s and `Option`s. The way it works is that, if you have a `None` or an `Error`,
it passes up the handling of this one level higher, by returning out of the function early with a `None` or `Error` value itself.
Of course, since return types of functions have to be known at compile time, the question-mark operator only works inside
functions that already return `Result` or `Option`.
```rust
fn main() {
let x = 5;
let y = 10;
let z = 20;
match do_something(x, y, z) {
Some(result) => println!("Happy noises, {}", result),
None => println!("Sad noises"),
}
}
fn do_something(x: i32, y: i32, z: i32) -> Option<i32> {
let first_result = do_something_more(x, y)?;
let second_result = do_something_more(first_result, z)?;
Some(second_result)
}
fn do_something_more(x: i32, y: i32) -> Option<i32> {
Some(x + y)
}
```
The advantage of this is that you only have to handle your `None` case exactly once. You don't have to add pattern matching, or
conditionals, or `unwrap()`s all over the place, just a cute little question mark that delegates the handling to some logic
higher up.
_"But sammy!"_ you say, _"the compiler keeps shouting at me when I use the question mark on Options when my function
returns Result \`<-.\_.->´"_
Don't worry my frien! Even this has been considered!
First of all, why does the compiler get upset? It's because the question-mark operator returns the same type that it's used on,
and `Result` and `Option` are different types. Because of that, I thought I'd have to manually handle `None` cases in all
of my `Result`-returning functions. Until one day, I was reading through some documentation (I know, I know, I'm a nerd who reads
through documentation for fun and not just to find specific things) and discovered [Option::Ok_or()](https://doc.rust-lang.org/std/option/enum.Option.html#method.ok_or).
> Transforms the `Option<T>` into a `Result<T, E>`, mapping `Some(v)` to `Ok(v)` and `None` to `Err(err)`.
This was a life-changer to me, and it was just hiding right there in plain sight. Now I can easily turn a `None` where there shouldn't
be a `None` into an `Error` to pass up with my pawesome question-mark operator!
```rust
fn main() -> Result<(), String> {
let x = function_that_returns_option().ok_or("error message".to_owned())?;
// Instead of:
// let x = function_that_returns_option().unwrap();
// or any of the other ways to handle None
assert_eq!(x, ());
Ok(x)
}
fn function_that_returns_option() -> Option<()> {
return Some(());
}
```
The last thing I want to mention is both an example specific to `Option`s, and a more general tip about how I discovered this one.
There is this wonderful friend for all Rust developers, called Clippy. No, not the Paperclip from Microsoft Word, but
[A collection of lints to catch common mistakes and improve your Rust code](https://doc.rust-lang.org/stable/clippy/).
Clippy is automatically installed when you install Rust via `rustup`, and it runs a whole lot of checks against your code
to tell you what you can improve.
In my case, I had the following piece of code:
```rust
let insert = (
tracks::title.eq(match tag.title() {
Some(title) => Some(title.to_string()),
None => None,
}),
tracks::track_number.eq(match tag.track() {
Some(track) => Some(track as i32),
None => None,
}),
tracks::disc_number.eq(match tag.disk() {
Some(track) => Some(track as i32),
None => None,
}),
tracks::path.eq(match path.to_str() {
None => return Err(Error::msg("Could not get path")),
Some(path) => path.to_string(),
}),
tracks::year.eq(match tag.year() {
Some(year) => Some(year as i32),
None => None,
}),
tracks::album_id.eq(match album {
Some(album) => Some(album.id),
None => None,
}),
);
```
This code builds an insert statement for the database holding my music metadata, getting the values from the tags of a file.
The tag fields are all `Option`s, since the tags might be empty. The databse entries are also all `Option`s, (at least on the Rust side,
on the database they are just values marked as possibly being Null). So my intuitive idea to build this was to just go through all the entries,
match the tag, put in `Some(value)` if there is a value, and `None`if there is none.
It works, it's not wrong, but there is a cleaner and more readable way to do this. And clippy told me right away, I ran it
from my IDE, and it told me:
> Manual implementation of `Option::map`
Huh, okay. Let's check the [documentation](https://doc.rust-lang.org/std/option/enum.Option.html#method.map)
> Maps an `Option<T>` to `Option<U>` by applying a function to a contained value.
So basically exactly what I did with those `match` statements!
My IDE even had a button to just easily fix this automatically with one click:
```rust
let insert = (
tracks::title.eq(tag.title().map(|title| title.to_string())),
tracks::track_number.eq(tag.track().map(|track| track as i32)),
tracks::disc_number.eq(tag.disk().map(|track| track as i32)),
tracks::path.eq(match path.to_str() {
None => return Err(Error::msg("Could not get path")),
Some(path) => path.to_string(),
}),
tracks::year.eq(tag.year().map(|year| year as i32)),
tracks::album_id.eq(album.map(|album| album.id)),
);
```
Great, that looks a lot cleaner immediately!
Note how one of the lines was not changed, that's because that one sets a DB value which is `NOT NULL`, thus if the original `Option` is
a `None` it means something went wrong, and we should abort this insert and return with an Error.
And with that, we're done with my first blogpost about Rust, with hopefully many more to come!
As I said, I am still learning, and writing this is part of my learning process. That being said, if you find this interesting,
learned something from it, etc., feel free to leave me some feedback! I'd love to hear what you think!
And if I made mistakes, please also tell me. I'm always happy to learn more and to fix those mistakes so others can learn from them too.
Thank you so much for reading 💜

View file

@ -1,5 +1,6 @@
+++
title = "Hello there!"
template = "page.html"
+++
{{ image(src="/profile.jpeg", alt="Profile picture",

View file

@ -65,7 +65,12 @@
<footer class="footer">
<div class="footer__inner">
<div class="copyright copyright--user"><p>&copy; {currentYear} - CherryKitten</p><a href="/impressum">Impressum</a>
<div class="copyright copyright--user"><p>&copy; 2023 - CherryKitten</p><br>
<p><a href="/impressum">Impressum</a></p>
 
<p><a href="/rss.xml">RSS</a></p>
 
🐱
</div>
</div>
</footer>

View file

@ -111,7 +111,12 @@ all the relevant projects in my <a href="https://codeberg.org/CherryKitten/freec
<footer class="footer">
<div class="footer__inner">
<div class="copyright copyright--user"><p>&copy; {currentYear} - CherryKitten</p><a href="/impressum">Impressum</a>
<div class="copyright copyright--user"><p>&copy; 2023 - CherryKitten</p><br>
<p><a href="/impressum">Impressum</a></p>
 
<p><a href="/rss.xml">RSS</a></p>
 
🐱
</div>
</div>
</footer>

View file

@ -133,6 +133,22 @@ Welcome to the Fediverse 💜.</p>
</div>
<div class="pagination">
<div class="pagination__title">
<span class="pagination__title-h">More posts!</span>
<hr />
</div>
<div class="pagination__buttons">
<span class="button next">
<a href="https://cherrykitten.dev/blog/rust-1-options-results/">
<span class="button__text">Learning Rust Part 1: A kitten&#x27;s guide to Options and Results</span>&nbsp;
<span class="button__icon"></span>
</a>
</span>
</div>
</div>
</div>
</div>
@ -140,7 +156,12 @@ Welcome to the Fediverse 💜.</p>
<footer class="footer">
<div class="footer__inner">
<div class="copyright copyright--user"><p>&copy; {currentYear} - CherryKitten</p><a href="/impressum">Impressum</a>
<div class="copyright copyright--user"><p>&copy; 2023 - CherryKitten</p><br>
<p><a href="/impressum">Impressum</a></p>
 
<p><a href="/rss.xml">RSS</a></p>
 
🐱
</div>
</div>
</footer>

View file

@ -57,6 +57,59 @@
<div class="posts">
<div class="post on-list">
<h1 class="post-title"><a href="https://cherrykitten.dev/blog/rust-1-options-results/">Learning Rust Part 1: A kitten&#x27;s guide to Options and Results</a></h1>
<div class="post-meta-inline">
<span class="post-date">
2023-02-25
</span>
</div>
<span class="post-tags-inline">
:: tags:&nbsp;
<a class="post-tag" href="https://cherrykitten.dev/tags/rust/">#Rust</a>&nbsp;
<a class="post-tag" href="https://cherrykitten.dev/tags/programming/">#programming</a>&nbsp;
<a class="post-tag" href="https://cherrykitten.dev/tags/code/">#code</a>&nbsp;
<a class="post-tag" href="https://cherrykitten.dev/tags/learning/">#learning</a></span>
<div class="post-content">
<h3 id="to-unwrap-or-not-to-unwrap-that-is-the-question">To unwrap() or not to unwrap(), that is the question:</h3>
<p>So I've finally given in and started to learn Rust last month. It's a really cool programming language,
with some interesting differences to what I've used before. (JavaScript and Python, mostly)</p>
<p>There are some really pawesome guides out there, <a href="https://doc.rust-lang.org/book/">&quot;The Rust programming language&quot;</a> is
definitely a <strong>must-read</strong> in my opinion, and <a href="https://github.com/rust-lang/rustlings">Rustlings</a> is nyamazing for
anyone who likes to learn by actively working through interactive problems.</p>
<p>After reading through a lot of those big thorough guides by experienced Rust developers, I've started working on
my first actual Project. I approached the development of this project by just trying to get small parts of it
working in any way I can manage, and then build upon this. In that process, I learned a lot of small subtilties that
guides like the ones named above just can't really cover. This post is for sharing those things, those cool little
tips to make your first Rust project just a little cleaner and more Rust-y. Originally I wanted to make this about a lot
of different topics, but then I've realized that my notes already contain so many things about just one part of Rust:
The Enums <code>Option</code> and <code>Result</code>. So this post will be about those, and hopefully will mark the start of a series on this blog.</p>
<p>While reading through this, you might think that the things I'm mentioning are obvious. That's okay, and that's the point.
Nothing is ever completely obvious to everyone, and this is for those like me, who often don't immediately recognize
the &quot;obvious&quot;. And, to be honest, I am writing this just as much for myself, writing all of that stuff down to aid me in my
own ongoing learning process.</p>
<p>So, let's start!</p>
</div>
<div>
<!-- &#xFE0E; -- force text style - some devices render this as emoji -->
<a class="read-more button" href="https://cherrykitten.dev/blog/rust-1-options-results/">
<span class="button__text">Read more</span>&nbsp;
<span class="button__icon">&#8617;&#xFE0E;</span>
</a>
</div>
</div>
<div class="post on-list">
<h1 class="post-title"><a href="https://cherrykitten.dev/blog/fediverse-isnt-just-mastodon/">The Fediverse is more than just Mastodon</a></h1>
<div class="post-meta-inline">
@ -103,7 +156,12 @@ People have been recommending &quot;Mastodon&quot; as a Twitter alternative for
<footer class="footer">
<div class="footer__inner">
<div class="copyright copyright--user"><p>&copy; {currentYear} - CherryKitten</p><a href="/impressum">Impressum</a>
<div class="copyright copyright--user"><p>&copy; 2023 - CherryKitten</p><br>
<p><a href="/impressum">Impressum</a></p>
 
<p><a href="/rss.xml">RSS</a></p>
 
🐱
</div>
</div>
</footer>

View file

@ -0,0 +1,324 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>Learning Rust Part 1: A kitten&#x27;s guide to Options and Results | CherryKitten</title>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1">
<meta name="robots" content="noodp"/>
<link rel="stylesheet" href="https://cherrykitten.dev/style.css">
<link rel="stylesheet" href="https://cherrykitten.dev/color/rosepine.css">
<link rel="stylesheet" href="https://cherrykitten.dev/font-hack-subset.css">
<link rel="alternate" type="application/rss+xml" title="RSS" href="https://cherrykitten.dev/rss.xml">
</head>
<body class="">
<div class="container">
<header class="header">
<div class="header__inner">
<div class="header__logo">
<a href="https://cherrykitten.dev" style="text-decoration: none;">
<div class="logo">
CherryKitten
</div>
</a>
</div>
</div>
<nav class="menu">
<ul class="menu__inner">
<li><a href="https://cherrykitten.dev">Home</a></li>
<li><a href="https://cherrykitten.dev/about">About me</a></li>
<li class="active"><a href="https://cherrykitten.dev/blog">Blog</a></li>
<li><a href="https://cherrykitten.dev/contact">Contact</a></li>
</ul>
</nav>
</header>
<div class="content">
<div class="post">
<h1 class="post-title"><a href="https://cherrykitten.dev/blog/rust-1-options-results/">Learning Rust Part 1: A kitten&#x27;s guide to Options and Results</a></h1>
<div class="post-meta-inline">
<span class="post-date">
2023-02-25
</span>
</div>
<span class="post-tags-inline">
:: tags:&nbsp;
<a class="post-tag" href="https://cherrykitten.dev/tags/rust/">#Rust</a>&nbsp;
<a class="post-tag" href="https://cherrykitten.dev/tags/programming/">#programming</a>&nbsp;
<a class="post-tag" href="https://cherrykitten.dev/tags/code/">#code</a>&nbsp;
<a class="post-tag" href="https://cherrykitten.dev/tags/learning/">#learning</a></span>
<div class="post-content">
<h3 id="to-unwrap-or-not-to-unwrap-that-is-the-question">To unwrap() or not to unwrap(), that is the question:</h3>
<p>So I've finally given in and started to learn Rust last month. It's a really cool programming language,
with some interesting differences to what I've used before. (JavaScript and Python, mostly)</p>
<p>There are some really pawesome guides out there, <a href="https://doc.rust-lang.org/book/">&quot;The Rust programming language&quot;</a> is
definitely a <strong>must-read</strong> in my opinion, and <a href="https://github.com/rust-lang/rustlings">Rustlings</a> is nyamazing for
anyone who likes to learn by actively working through interactive problems.</p>
<p>After reading through a lot of those big thorough guides by experienced Rust developers, I've started working on
my first actual Project. I approached the development of this project by just trying to get small parts of it
working in any way I can manage, and then build upon this. In that process, I learned a lot of small subtilties that
guides like the ones named above just can't really cover. This post is for sharing those things, those cool little
tips to make your first Rust project just a little cleaner and more Rust-y. Originally I wanted to make this about a lot
of different topics, but then I've realized that my notes already contain so many things about just one part of Rust:
The Enums <code>Option</code> and <code>Result</code>. So this post will be about those, and hopefully will mark the start of a series on this blog.</p>
<p>While reading through this, you might think that the things I'm mentioning are obvious. That's okay, and that's the point.
Nothing is ever completely obvious to everyone, and this is for those like me, who often don't immediately recognize
the &quot;obvious&quot;. And, to be honest, I am writing this just as much for myself, writing all of that stuff down to aid me in my
own ongoing learning process.</p>
<p>So, let's start!</p>
<span id="continue-reading"></span>
<p>Firstly, a very quick introduction. <code>Option</code> and <code>Result</code> are part of the Rust standard library. Quoting the official documentation
is probably the easiest way to summarize their purpose:</p>
<blockquote>
<p>Type <code>Option</code> represents an optional value: every Option is either <code>Some</code> and contains a value, or <code>None</code>, and does not. <code>Option</code> types are very common in Rust code, as they have a number of uses:</p>
<ul>
<li>Initial values</li>
<li>Return values for functions that are not defined over their entire input range (partial functions)</li>
<li>Return value for otherwise reporting simple errors, where <code>None</code> is returned on error</li>
<li>Optional struct fields</li>
<li>Struct fields that can be loaned or “taken”</li>
<li>Optional function arguments</li>
<li>Nullable pointers</li>
<li>Swapping things out of difficult situations</li>
</ul>
</blockquote>
<p>and</p>
<blockquote>
<p><code>Result&lt;T, E&gt;</code> is the type used for returning and propagating errors. It is an enum with the variants, <code>Ok(T)</code>, representing success and containing a value, and <code>Err(E)</code>, representing error and containing an error value.</p>
</blockquote>
<p>At first, it seems so easy to just add a quick <code>.unwrap()</code> after every <code>Option</code> or <code>Result</code>, but this comes with
the disadvantage of your code <a href="https://doc.rust-lang.org/std/macro.panic.html">panicking</a> if it fails to unwrap.
Sometimes, this can be useful during development, to discover potential error cases you might not have thought about, but
is usually not what you want to happen.</p>
<p>So, what can you do instead?</p>
<p>First of all, don't use <code>unwrap()</code> unless you are completely sure that the value will never panic. Sometimes that is the
case, because an earlier part of your code already made sure that it is <code>Ok</code> or <code>Some</code>.</p>
<p>In some cases, you actually want the program to panic. But even then, there is a slightly better way. You can use <code>expect(&quot;foo&quot;)</code>
to add a message to the panic, so the user actually knows what went wrong. That message should be worded in a specific way,
basically telling the user what you <em>expected</em> to happen.</p>
<pre data-lang="rust" style="background-color:#1f1d29;color:#ffffff;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="font-style:italic;color:#9bced7;">fn </span><span style="color:#34738e;">main</span><span>() {
</span><span> </span><span style="font-style:italic;color:#9bced7;">let</span><span> x </span><span style="color:#ea6f91;">= </span><span style="font-style:italic;color:#66d9ef;">Some</span><span>(</span><span style="color:#f1ca93;">&quot;Hello, World&quot;</span><span>);
</span><span> </span><span style="color:#403c58;">// There is no actual &quot;None&quot; type/value in Rust,
</span><span> </span><span style="color:#403c58;">// this &quot;None&quot; is more specifically Option::None
</span><span> </span><span style="font-style:italic;color:#9bced7;">let</span><span> y: </span><span style="font-style:italic;color:#66d9ef;">Option</span><span>&lt;</span><span style="font-style:italic;color:#66d9ef;">String</span><span>&gt; </span><span style="color:#ea6f91;">= </span><span style="font-style:italic;color:#66d9ef;">None</span><span>;
</span><span>
</span><span> </span><span style="font-style:italic;color:#9bced7;">let</span><span> z </span><span style="color:#ea6f91;">=</span><span> x.</span><span style="color:#66d9ef;">unwrap</span><span>(); </span><span style="color:#403c58;">// We explicitly set this to Some, so we can safely unwrap it
</span><span> </span><span style="font-style:italic;color:#9bced7;">let</span><span> rip </span><span style="color:#ea6f91;">=</span><span> y.</span><span style="color:#66d9ef;">expect</span><span>(</span><span style="color:#f1ca93;">&quot;expected y to not be None&quot;</span><span>);
</span><span>
</span><span> println!(</span><span style="color:#f1ca93;">&quot;</span><span style="color:#c3a5e6;">{}</span><span style="color:#f1ca93;">, </span><span style="color:#c3a5e6;">{}</span><span style="color:#f1ca93;"> will never print because it panics above&quot;</span><span>, z, rip);
</span><span>}
</span></code></pre>
<p>There are also the non-panicking siblings of <code>unwrap()</code>, like <code>unwrap_or()</code>, <code>unwrap_or_else()</code> and <code>unwrap_or_default()</code>.</p>
<pre data-lang="rust" style="background-color:#1f1d29;color:#ffffff;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="font-style:italic;color:#9bced7;">fn </span><span style="color:#34738e;">main</span><span>() {
</span><span> </span><span style="font-style:italic;color:#9bced7;">let</span><span> a: </span><span style="font-style:italic;color:#66d9ef;">Option</span><span>&lt;</span><span style="font-style:italic;color:#66d9ef;">String</span><span>&gt; </span><span style="color:#ea6f91;">= </span><span style="font-style:italic;color:#66d9ef;">None</span><span>;
</span><span> </span><span style="font-style:italic;color:#9bced7;">let</span><span> b: </span><span style="font-style:italic;color:#66d9ef;">Option</span><span>&lt;</span><span style="font-style:italic;color:#9bced7;">i32</span><span>&gt; </span><span style="color:#ea6f91;">= </span><span style="font-style:italic;color:#66d9ef;">None</span><span>;
</span><span> </span><span style="font-style:italic;color:#9bced7;">let</span><span> c: </span><span style="font-style:italic;color:#66d9ef;">Option</span><span>&lt;</span><span style="font-style:italic;color:#9bced7;">bool</span><span>&gt; </span><span style="color:#ea6f91;">= </span><span style="font-style:italic;color:#66d9ef;">None</span><span>;
</span><span>
</span><span> </span><span style="color:#403c58;">// unwrap_or() lets you supply a specific value to use if the Option is None
</span><span> </span><span style="font-style:italic;color:#9bced7;">let</span><span> x </span><span style="color:#ea6f91;">=</span><span> a.</span><span style="color:#66d9ef;">unwrap_or</span><span>(</span><span style="color:#f1ca93;">&quot;Hello there&quot;</span><span>.</span><span style="color:#66d9ef;">to_owned</span><span>());
</span><span>
</span><span> </span><span style="color:#403c58;">// unwrap_or_default() uses the types default value if the Option is None
</span><span> </span><span style="font-style:italic;color:#9bced7;">let</span><span> y </span><span style="color:#ea6f91;">=</span><span> b.</span><span style="color:#66d9ef;">unwrap_or_default</span><span>();
</span><span>
</span><span> </span><span style="color:#403c58;">// unwrap_or_else() lets you specify a closure to run if the Option is None
</span><span> </span><span style="font-style:italic;color:#9bced7;">let</span><span> z </span><span style="color:#ea6f91;">=</span><span> c.</span><span style="color:#66d9ef;">unwrap_or_else</span><span>(|| </span><span style="color:#ea6f91;">if </span><span style="color:#c3a5e6;">1 </span><span style="color:#ea6f91;">+ </span><span style="color:#c3a5e6;">1 </span><span style="color:#ea6f91;">== </span><span style="color:#c3a5e6;">2 </span><span>{ </span><span style="color:#c3a5e6;">true</span><span>} </span><span style="color:#ea6f91;">else </span><span>{ </span><span style="color:#c3a5e6;">false </span><span>});
</span><span>
</span><span> assert_eq!(x, </span><span style="color:#f1ca93;">&quot;Hello there&quot;</span><span>.</span><span style="color:#66d9ef;">to_owned</span><span>());
</span><span> assert_eq!(y, </span><span style="color:#c3a5e6;">0</span><span>);
</span><span> assert_eq!(z, </span><span style="color:#c3a5e6;">true</span><span>);
</span><span>}
</span></code></pre>
<p>And then there is this really cool question-mark operator, which comes in very handy once you go multiple functions deep
and keep having to work with more and more <code>Result</code>s and <code>Option</code>s. The way it works is that, if you have a <code>None</code> or an <code>Error</code>,
it passes up the handling of this one level higher, by returning out of the function early with a <code>None</code> or <code>Error</code> value itself.</p>
<p>Of course, since return types of functions have to be known at compile time, the question-mark operator only works inside
functions that already return <code>Result</code> or <code>Option</code>.</p>
<pre data-lang="rust" style="background-color:#1f1d29;color:#ffffff;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="font-style:italic;color:#9bced7;">fn </span><span style="color:#34738e;">main</span><span>() {
</span><span> </span><span style="font-style:italic;color:#9bced7;">let</span><span> x </span><span style="color:#ea6f91;">= </span><span style="color:#c3a5e6;">5</span><span>;
</span><span> </span><span style="font-style:italic;color:#9bced7;">let</span><span> y </span><span style="color:#ea6f91;">= </span><span style="color:#c3a5e6;">10</span><span>;
</span><span> </span><span style="font-style:italic;color:#9bced7;">let</span><span> z </span><span style="color:#ea6f91;">= </span><span style="color:#c3a5e6;">20</span><span>;
</span><span>
</span><span> </span><span style="color:#ea6f91;">match </span><span style="color:#66d9ef;">do_something</span><span>(x, y, z) {
</span><span> </span><span style="font-style:italic;color:#66d9ef;">Some</span><span>(result) </span><span style="color:#ea6f91;">=&gt; </span><span>println!(</span><span style="color:#f1ca93;">&quot;Happy noises, </span><span style="color:#c3a5e6;">{}</span><span style="color:#f1ca93;">&quot;</span><span>, result),
</span><span> </span><span style="font-style:italic;color:#66d9ef;">None </span><span style="color:#ea6f91;">=&gt; </span><span>println!(</span><span style="color:#f1ca93;">&quot;Sad noises&quot;</span><span>),
</span><span> }
</span><span>}
</span><span>
</span><span style="font-style:italic;color:#9bced7;">fn </span><span style="color:#34738e;">do_something</span><span>(</span><span style="font-style:italic;color:#f1ca93;">x</span><span>: </span><span style="font-style:italic;color:#9bced7;">i32</span><span>, </span><span style="font-style:italic;color:#f1ca93;">y</span><span>: </span><span style="font-style:italic;color:#9bced7;">i32</span><span>, </span><span style="font-style:italic;color:#f1ca93;">z</span><span>: </span><span style="font-style:italic;color:#9bced7;">i32</span><span>) -&gt; </span><span style="font-style:italic;color:#66d9ef;">Option</span><span>&lt;</span><span style="font-style:italic;color:#9bced7;">i32</span><span>&gt; {
</span><span> </span><span style="font-style:italic;color:#9bced7;">let</span><span> first_result </span><span style="color:#ea6f91;">= </span><span style="color:#66d9ef;">do_something_more</span><span>(x, y)</span><span style="color:#ea6f91;">?</span><span>;
</span><span> </span><span style="font-style:italic;color:#9bced7;">let</span><span> second_result </span><span style="color:#ea6f91;">= </span><span style="color:#66d9ef;">do_something_more</span><span>(first_result, z)</span><span style="color:#ea6f91;">?</span><span>;
</span><span>
</span><span> </span><span style="font-style:italic;color:#66d9ef;">Some</span><span>(second_result)
</span><span>}
</span><span>
</span><span style="font-style:italic;color:#9bced7;">fn </span><span style="color:#34738e;">do_something_more</span><span>(</span><span style="font-style:italic;color:#f1ca93;">x</span><span>: </span><span style="font-style:italic;color:#9bced7;">i32</span><span>, </span><span style="font-style:italic;color:#f1ca93;">y</span><span>: </span><span style="font-style:italic;color:#9bced7;">i32</span><span>) -&gt; </span><span style="font-style:italic;color:#66d9ef;">Option</span><span>&lt;</span><span style="font-style:italic;color:#9bced7;">i32</span><span>&gt; {
</span><span> </span><span style="font-style:italic;color:#66d9ef;">Some</span><span>(x </span><span style="color:#ea6f91;">+</span><span> y)
</span><span>}
</span></code></pre>
<p>The advantage of this is that you only have to handle your <code>None</code> case exactly once. You don't have to add pattern matching, or
conditionals, or <code>unwrap()</code>s all over the place, just a cute little question mark that delegates the handling to some logic
higher up.</p>
<p><em>&quot;But sammy!&quot;</em> you say, <em>&quot;the compiler keeps shouting at me when I use the question mark on Options when my function
returns Result `&lt;-._.-&gt;´&quot;</em></p>
<p>Don't worry my frien! Even this has been considered!</p>
<p>First of all, why does the compiler get upset? It's because the question-mark operator returns the same type that it's used on,
and <code>Result</code> and <code>Option</code> are different types. Because of that, I thought I'd have to manually handle <code>None</code> cases in all
of my <code>Result</code>-returning functions. Until one day, I was reading through some documentation (I know, I know, I'm a nerd who reads
through documentation for fun and not just to find specific things) and discovered <a href="https://doc.rust-lang.org/std/option/enum.Option.html#method.ok_or">Option::Ok_or()</a>.</p>
<blockquote>
<p>Transforms the <code>Option&lt;T&gt;</code> into a <code>Result&lt;T, E&gt;</code>, mapping <code>Some(v)</code> to <code>Ok(v)</code> and <code>None</code> to <code>Err(err)</code>.</p>
</blockquote>
<p>This was a life-changer to me, and it was just hiding right there in plain sight. Now I can easily turn a <code>None</code> where there shouldn't
be a <code>None</code> into an <code>Error</code> to pass up with my pawesome question-mark operator!</p>
<pre data-lang="rust" style="background-color:#1f1d29;color:#ffffff;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="font-style:italic;color:#9bced7;">fn </span><span style="color:#34738e;">main</span><span>() -&gt; </span><span style="font-style:italic;color:#66d9ef;">Result</span><span>&lt;(), </span><span style="font-style:italic;color:#66d9ef;">String</span><span>&gt; {
</span><span> </span><span style="font-style:italic;color:#9bced7;">let</span><span> x </span><span style="color:#ea6f91;">= </span><span style="color:#66d9ef;">function_that_returns_option</span><span>().</span><span style="color:#66d9ef;">ok_or</span><span>(</span><span style="color:#f1ca93;">&quot;error message&quot;</span><span>.</span><span style="color:#66d9ef;">to_owned</span><span>())</span><span style="color:#ea6f91;">?</span><span>;
</span><span> </span><span style="color:#403c58;">// Instead of:
</span><span> </span><span style="color:#403c58;">// let x = function_that_returns_option().unwrap();
</span><span> </span><span style="color:#403c58;">// or any of the other ways to handle None
</span><span>
</span><span> assert_eq!(x, ());
</span><span> </span><span style="font-style:italic;color:#66d9ef;">Ok</span><span>(x)
</span><span>}
</span><span>
</span><span style="font-style:italic;color:#9bced7;">fn </span><span style="color:#34738e;">function_that_returns_option</span><span>() -&gt; </span><span style="font-style:italic;color:#66d9ef;">Option</span><span>&lt;()&gt; {
</span><span> </span><span style="color:#ea6f91;">return </span><span style="font-style:italic;color:#66d9ef;">Some</span><span>(());
</span><span>}
</span></code></pre>
<p>The last thing I want to mention is both an example specific to <code>Option</code>s, and a more general tip about how I discovered this one.
There is this wonderful friend for all Rust developers, called Clippy. No, not the Paperclip from Microsoft Word, but
<a href="https://doc.rust-lang.org/stable/clippy/">A collection of lints to catch common mistakes and improve your Rust code</a>.
Clippy is automatically installed when you install Rust via <code>rustup</code>, and it runs a whole lot of checks against your code
to tell you what you can improve.</p>
<p>In my case, I had the following piece of code:</p>
<pre data-lang="rust" style="background-color:#1f1d29;color:#ffffff;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="font-style:italic;color:#9bced7;">let</span><span> insert </span><span style="color:#ea6f91;">= </span><span>(
</span><span> tracks::title.</span><span style="color:#66d9ef;">eq</span><span>(</span><span style="color:#ea6f91;">match</span><span> tag.</span><span style="color:#66d9ef;">title</span><span>() {
</span><span> </span><span style="font-style:italic;color:#66d9ef;">Some</span><span>(title) </span><span style="color:#ea6f91;">=&gt; </span><span style="font-style:italic;color:#66d9ef;">Some</span><span>(title.</span><span style="color:#66d9ef;">to_string</span><span>()),
</span><span> </span><span style="font-style:italic;color:#66d9ef;">None </span><span style="color:#ea6f91;">=&gt; </span><span style="font-style:italic;color:#66d9ef;">None</span><span>,
</span><span> }),
</span><span> tracks::track_number.</span><span style="color:#66d9ef;">eq</span><span>(</span><span style="color:#ea6f91;">match</span><span> tag.</span><span style="color:#66d9ef;">track</span><span>() {
</span><span> </span><span style="font-style:italic;color:#66d9ef;">Some</span><span>(track) </span><span style="color:#ea6f91;">=&gt; </span><span style="font-style:italic;color:#66d9ef;">Some</span><span>(track </span><span style="color:#ea6f91;">as </span><span style="font-style:italic;color:#9bced7;">i32</span><span>),
</span><span> </span><span style="font-style:italic;color:#66d9ef;">None </span><span style="color:#ea6f91;">=&gt; </span><span style="font-style:italic;color:#66d9ef;">None</span><span>,
</span><span> }),
</span><span> tracks::disc_number.</span><span style="color:#66d9ef;">eq</span><span>(</span><span style="color:#ea6f91;">match</span><span> tag.</span><span style="color:#66d9ef;">disk</span><span>() {
</span><span> </span><span style="font-style:italic;color:#66d9ef;">Some</span><span>(track) </span><span style="color:#ea6f91;">=&gt; </span><span style="font-style:italic;color:#66d9ef;">Some</span><span>(track </span><span style="color:#ea6f91;">as </span><span style="font-style:italic;color:#9bced7;">i32</span><span>),
</span><span> </span><span style="font-style:italic;color:#66d9ef;">None </span><span style="color:#ea6f91;">=&gt; </span><span style="font-style:italic;color:#66d9ef;">None</span><span>,
</span><span> }),
</span><span> tracks::path.</span><span style="color:#66d9ef;">eq</span><span>(</span><span style="color:#ea6f91;">match</span><span> path.</span><span style="color:#66d9ef;">to_str</span><span>() {
</span><span> </span><span style="font-style:italic;color:#66d9ef;">None </span><span style="color:#ea6f91;">=&gt; return </span><span style="font-style:italic;color:#66d9ef;">Err</span><span>(Error::msg(</span><span style="color:#f1ca93;">&quot;Could not get path&quot;</span><span>)),
</span><span> </span><span style="font-style:italic;color:#66d9ef;">Some</span><span>(path) </span><span style="color:#ea6f91;">=&gt;</span><span> path.</span><span style="color:#66d9ef;">to_string</span><span>(),
</span><span> }),
</span><span> tracks::year.</span><span style="color:#66d9ef;">eq</span><span>(</span><span style="color:#ea6f91;">match</span><span> tag.</span><span style="color:#66d9ef;">year</span><span>() {
</span><span> </span><span style="font-style:italic;color:#66d9ef;">Some</span><span>(year) </span><span style="color:#ea6f91;">=&gt; </span><span style="font-style:italic;color:#66d9ef;">Some</span><span>(year </span><span style="color:#ea6f91;">as </span><span style="font-style:italic;color:#9bced7;">i32</span><span>),
</span><span> </span><span style="font-style:italic;color:#66d9ef;">None </span><span style="color:#ea6f91;">=&gt; </span><span style="font-style:italic;color:#66d9ef;">None</span><span>,
</span><span> }),
</span><span> tracks::album_id.</span><span style="color:#66d9ef;">eq</span><span>(</span><span style="color:#ea6f91;">match</span><span> album {
</span><span> </span><span style="font-style:italic;color:#66d9ef;">Some</span><span>(album) </span><span style="color:#ea6f91;">=&gt; </span><span style="font-style:italic;color:#66d9ef;">Some</span><span>(album.id),
</span><span> </span><span style="font-style:italic;color:#66d9ef;">None </span><span style="color:#ea6f91;">=&gt; </span><span style="font-style:italic;color:#66d9ef;">None</span><span>,
</span><span> }),
</span><span> );
</span></code></pre>
<p>This code builds an insert statement for the database holding my music metadata, getting the values from the tags of a file.
The tag fields are all <code>Option</code>s, since the tags might be empty. The databse entries are also all <code>Option</code>s, (at least on the Rust side,
on the database they are just values marked as possibly being Null). So my intuitive idea to build this was to just go through all the entries,
match the tag, put in <code>Some(value)</code> if there is a value, and <code>None</code>if there is none.</p>
<p>It works, it's not wrong, but there is a cleaner and more readable way to do this. And clippy told me right away, I ran it
from my IDE, and it told me:</p>
<blockquote>
<p>Manual implementation of <code>Option::map</code></p>
</blockquote>
<p>Huh, okay. Let's check the <a href="https://doc.rust-lang.org/std/option/enum.Option.html#method.map">documentation</a> </p>
<blockquote>
<p>Maps an <code>Option&lt;T&gt;</code> to <code>Option&lt;U&gt;</code> by applying a function to a contained value.</p>
</blockquote>
<p>So basically exactly what I did with those <code>match</code> statements!
My IDE even had a button to just easily fix this automatically with one click:</p>
<pre data-lang="rust" style="background-color:#1f1d29;color:#ffffff;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="font-style:italic;color:#9bced7;">let</span><span> insert </span><span style="color:#ea6f91;">= </span><span>(
</span><span> tracks::title.</span><span style="color:#66d9ef;">eq</span><span>(tag.</span><span style="color:#66d9ef;">title</span><span>().</span><span style="color:#66d9ef;">map</span><span>(|</span><span style="font-style:italic;color:#f1ca93;">title</span><span>| title.</span><span style="color:#66d9ef;">to_string</span><span>())),
</span><span> tracks::track_number.</span><span style="color:#66d9ef;">eq</span><span>(tag.</span><span style="color:#66d9ef;">track</span><span>().</span><span style="color:#66d9ef;">map</span><span>(|</span><span style="font-style:italic;color:#f1ca93;">track</span><span>| track </span><span style="color:#ea6f91;">as </span><span style="font-style:italic;color:#9bced7;">i32</span><span>)),
</span><span> tracks::disc_number.</span><span style="color:#66d9ef;">eq</span><span>(tag.</span><span style="color:#66d9ef;">disk</span><span>().</span><span style="color:#66d9ef;">map</span><span>(|</span><span style="font-style:italic;color:#f1ca93;">track</span><span>| track </span><span style="color:#ea6f91;">as </span><span style="font-style:italic;color:#9bced7;">i32</span><span>)),
</span><span> tracks::path.</span><span style="color:#66d9ef;">eq</span><span>(</span><span style="color:#ea6f91;">match</span><span> path.</span><span style="color:#66d9ef;">to_str</span><span>() {
</span><span> </span><span style="font-style:italic;color:#66d9ef;">None </span><span style="color:#ea6f91;">=&gt; return </span><span style="font-style:italic;color:#66d9ef;">Err</span><span>(Error::msg(</span><span style="color:#f1ca93;">&quot;Could not get path&quot;</span><span>)),
</span><span> </span><span style="font-style:italic;color:#66d9ef;">Some</span><span>(path) </span><span style="color:#ea6f91;">=&gt;</span><span> path.</span><span style="color:#66d9ef;">to_string</span><span>(),
</span><span> }),
</span><span> tracks::year.</span><span style="color:#66d9ef;">eq</span><span>(tag.</span><span style="color:#66d9ef;">year</span><span>().</span><span style="color:#66d9ef;">map</span><span>(|</span><span style="font-style:italic;color:#f1ca93;">year</span><span>| year </span><span style="color:#ea6f91;">as </span><span style="font-style:italic;color:#9bced7;">i32</span><span>)),
</span><span> tracks::album_id.</span><span style="color:#66d9ef;">eq</span><span>(album.</span><span style="color:#66d9ef;">map</span><span>(|</span><span style="font-style:italic;color:#f1ca93;">album</span><span>| album.id)),
</span><span> );
</span></code></pre>
<p>Great, that looks a lot cleaner immediately!
Note how one of the lines was not changed, that's because that one sets a DB value which is <code>NOT NULL</code>, thus if the original <code>Option</code> is
a <code>None</code> it means something went wrong, and we should abort this insert and return with an Error.</p>
<p>And with that, we're done with my first blogpost about Rust, with hopefully many more to come!
As I said, I am still learning, and writing this is part of my learning process. That being said, if you find this interesting,
learned something from it, etc., feel free to leave me some feedback! I'd love to hear what you think!
And if I made mistakes, please also tell me. I'm always happy to learn more and to fix those mistakes so others can learn from them too.</p>
<p>Thank you so much for reading 💜</p>
</div>
<div class="pagination">
<div class="pagination__title">
<span class="pagination__title-h">More posts!</span>
<hr />
</div>
<div class="pagination__buttons">
<span class="button previous">
<a href="https://cherrykitten.dev/blog/fediverse-isnt-just-mastodon/">
<span class="button__icon"></span>&nbsp;
<span class="button__text">The Fediverse is more than just Mastodon</span>
</a>
</span>
</div>
</div>
</div>
</div>
<footer class="footer">
<div class="footer__inner">
<div class="copyright copyright--user"><p>&copy; 2023 - CherryKitten</p><br>
<p><a href="/impressum">Impressum</a></p>
 
<p><a href="/rss.xml">RSS</a></p>
 
🐱
</div>
</div>
</footer>
</div>
</body>
</html>

View file

@ -1 +1 @@
.button-container{display:table;margin-left:auto;margin-right:auto}button,.button,a.button{position:relative;display:flex;align-items:center;justify-content:center;padding:8px 18px;margin-bottom:5px;text-align:center;border-radius:8px;border:1px solid transparent;appearance:none;cursor:pointer;outline:none}button.outline,.button.outline,a.button.outline{background:transparent;box-shadow:none;padding:8px 18px}button.outline :hover,.button.outline :hover,a.button.outline :hover{transform:none;box-shadow:none}button.primary,.button.primary,a.button.primary{box-shadow:0 4px 6px rgba(50,50,93,0.11),0 1px 3px rgba(0,0,0,0.08)}button.primary:hover,.button.primary:hover,a.button.primary:hover{box-shadow:0 2px 6px rgba(50,50,93,0.21),0 1px 3px rgba(0,0,0,0.08)}button.link,.button.link,a.button.link{background:none;font-size:1rem}button.small,.button.small,a.button.small{font-size:.8rem}button.wide,.button.wide,a.button.wide{min-width:200px;padding:14px 24px}a.read-more,a.read-more:hover,a.read-more:active{display:inline-flex;background:none;box-shadow:none;padding:0;margin:20px 0;max-width:100%}.code-toolbar{margin-bottom:20px}.code-toolbar .toolbar-item a{position:relative;display:inline-flex;align-items:center;justify-content:center;padding:3px 8px;margin-bottom:5px;text-align:center;font-size:13px;font-weight:500;border-radius:8px;border:1px solid transparent;appearance:none;cursor:pointer;outline:none}
.button-container{display:table;margin-left:auto;margin-right:auto}button,.button,a.button{position:relative;display:flex;align-items:center;justify-content:center;padding:8px 18px;margin-bottom:5px;text-align:center;border-radius:8px;border:1px solid rgba(0,0,0,0);appearance:none;cursor:pointer;outline:none;}button.outline,.button.outline,a.button.outline{background:rgba(0,0,0,0);box-shadow:none;padding:8px 18px}button.outline :hover,.button.outline :hover,a.button.outline :hover{transform:none;box-shadow:none}button.primary,.button.primary,a.button.primary{box-shadow:0 4px 6px rgba(50,50,93,.11),0 1px 3px rgba(0,0,0,.08)}button.primary:hover,.button.primary:hover,a.button.primary:hover{box-shadow:0 2px 6px rgba(50,50,93,.21),0 1px 3px rgba(0,0,0,.08)}button.link,.button.link,a.button.link{background:none;font-size:1rem}button.small,.button.small,a.button.small{font-size:.8rem}button.wide,.button.wide,a.button.wide{min-width:200px;padding:14px 24px}a.read-more,a.read-more:hover,a.read-more:active{display:inline-flex;background:none;box-shadow:none;padding:0;margin:20px 0;max-width:100%}.code-toolbar{margin-bottom:20px}.code-toolbar .toolbar-item a{position:relative;display:inline-flex;align-items:center;justify-content:center;padding:3px 8px;margin-bottom:5px;text-align:center;font-size:13px;font-weight:500;border-radius:8px;border:1px solid rgba(0,0,0,0);appearance:none;cursor:pointer;outline:none}

View file

@ -1 +1 @@
:root{--background: #1D212C}
:root{--background: #1D212C}

View file

@ -1 +1 @@
:root{--background: #101010;--color: #A9B7C6}
:root{--background: #101010;--color: #A9B7C6}

View file

@ -1 +1 @@
:root{--background: #1F222A}
:root{--background: #1F222A}

View file

@ -1 +1 @@
:root{--background: #222129}
:root{--background: #222129}

View file

@ -1 +1 @@
:root{--background: #21202C}
:root{--background: #21202C}

View file

@ -1 +1 @@
:root{--background: #221F29}
:root{--background: #221F29}

View file

@ -1 +1 @@
:root{--background: #232136;--color: #3e8fb0}
:root{--background: #232136;--color: #3e8fb0}

View file

@ -1 +1 @@
:root{--accent: rgb(35,176,255);--accent-alpha-70: rgba(35,176,255,.7);--accent-alpha-20: rgba(35,176,255,.2);--background: #1D212C;--color: white;--border-color: rgba(255, 255, 255, .1)}
:root{--accent: rgb(35,176,255);--accent-alpha-70: rgba(35,176,255,.7);--accent-alpha-20: rgba(35,176,255,.2);--background: #1D212C;--color: white;--border-color: rgba(255, 255, 255, .1)}

View file

@ -1 +1 @@
:root{--accent: rgb(120,226,160);--accent-alpha-70: rgba(120,226,160,.7);--accent-alpha-20: rgba(120,226,160,.2);--background: #1F222A;--color: white;--border-color: rgba(255, 255, 255, .1)}
:root{--accent: rgb(120,226,160);--accent-alpha-70: rgba(120,226,160,.7);--accent-alpha-20: rgba(120,226,160,.2);--background: #1F222A;--color: white;--border-color: rgba(255, 255, 255, .1)}

View file

@ -1 +1 @@
:root{--accent: rgb(255,168,106);--accent-alpha-70: rgba(255,168,106,.7);--accent-alpha-20: rgba(255,168,106,.2);--background: #222129;--color: white;--border-color: rgba(255, 255, 255, .1)}
:root{--accent: rgb(255,168,106);--accent-alpha-70: rgba(255,168,106,.7);--accent-alpha-20: rgba(255,168,106,.2);--background: #222129;--color: white;--border-color: rgba(255, 255, 255, .1)}

View file

@ -1 +1 @@
:root{--accent: rgb(238,114,241);--accent-alpha-70: rgba(238,114,241,.7);--accent-alpha-20: rgba(238,114,241,.2);--background: #21202C;--color: white;--border-color: rgba(255, 255, 255, .1)}
:root{--accent: rgb(238,114,241);--accent-alpha-70: rgba(238,114,241,.7);--accent-alpha-20: rgba(238,114,241,.2);--background: #21202C;--color: white;--border-color: rgba(255, 255, 255, .1)}

View file

@ -1 +1 @@
:root{--accent: rgb(255,98,102);--accent-alpha-70: rgba(255,98,102,.7);--accent-alpha-20: rgba(255,98,102,.2);--background: #221F29;--color: white;--border-color: rgba(255, 255, 255, .1)}
:root{--accent: rgb(255,98,102);--accent-alpha-70: rgba(255,98,102,.7);--accent-alpha-20: rgba(255,98,102,.2);--background: #221F29;--color: white;--border-color: rgba(255, 255, 255, .1)}

View file

@ -1 +1 @@
:root{--accent: rgb(235, 111, 146);--accent2: rgb(246, 193, 119);--accent3: rgb(62, 143, 176);--accent-alpha-70: rgba(235, 111, 146,.7);--accent-alpha-20: rgba(235, 111, 146,.2);--background: #232136;--color: #e0def4;--border-color: rgba(246, 193, 119, .1)}
:root{--accent: rgb(235, 111, 146);--accent2: rgb(246, 193, 119);--accent3: rgb(62, 143, 176);--accent-alpha-70: rgba(235, 111, 146,.7);--accent-alpha-20: rgba(235, 111, 146,.2);--background: #232136;--color: #e0def4;--border-color: rgba(246, 193, 119, .1)}

View file

@ -141,7 +141,12 @@
<footer class="footer">
<div class="footer__inner">
<div class="copyright copyright--user"><p>&copy; {currentYear} - CherryKitten</p><a href="/impressum">Impressum</a>
<div class="copyright copyright--user"><p>&copy; 2023 - CherryKitten</p><br>
<p><a href="/impressum">Impressum</a></p>
 
<p><a href="/rss.xml">RSS</a></p>
 
🐱
</div>
</div>
</footer>

View file

@ -1,4 +1,4 @@
/*!
* Hack typeface https://github.com/source-foundry/Hack
* License: https://github.com/source-foundry/Hack/blob/master/LICENSE.md
*/@font-face{font-family:'Hack';src:url("fonts/hack-regular.woff2?sha=3114f1256") format("woff2"),url("fonts/hack-regular.woff?sha=3114f1256") format("woff");font-weight:400;font-style:normal}@font-face{font-family:'Hack';src:url("fonts/hack-bold-subset.woff2?sha=3114f1256") format("woff2"),url("fonts/hack-bold-subset.woff?sha=3114f1256") format("woff");font-weight:700;font-style:normal}@font-face{font-family:'Hack';src:url("fonts/hack-italic-subset.woff2?sha=3114f1256") format("woff2"),url("fonts/hack-italic-webfont.woff?sha=3114f1256") format("woff");font-weight:400;font-style:italic}@font-face{font-family:'Hack';src:url("fonts/hack-bolditalic-subset.woff2?sha=3114f1256") format("woff2"),url("fonts/hack-bolditalic-subset.woff?sha=3114f1256") format("woff");font-weight:700;font-style:italic}
*/@font-face{font-family:"Hack";src:url("fonts/hack-regular.woff2?sha=3114f1256") format("woff2"),url("fonts/hack-regular.woff?sha=3114f1256") format("woff");font-weight:400;font-style:normal}@font-face{font-family:"Hack";src:url("fonts/hack-bold-subset.woff2?sha=3114f1256") format("woff2"),url("fonts/hack-bold-subset.woff?sha=3114f1256") format("woff");font-weight:700;font-style:normal}@font-face{font-family:"Hack";src:url("fonts/hack-italic-subset.woff2?sha=3114f1256") format("woff2"),url("fonts/hack-italic-webfont.woff?sha=3114f1256") format("woff");font-weight:400;font-style:italic}@font-face{font-family:"Hack";src:url("fonts/hack-bolditalic-subset.woff2?sha=3114f1256") format("woff2"),url("fonts/hack-bolditalic-subset.woff?sha=3114f1256") format("woff");font-weight:700;font-style:italic}

View file

@ -1,4 +1,4 @@
/*!
* Hack typeface https://github.com/source-foundry/Hack
* License: https://github.com/source-foundry/Hack/blob/master/LICENSE.md
*/@font-face{font-family:'Hack';src:url("fonts/hack-regular.woff2?sha=3114f1256") format("woff2"),url("fonts/hack-regular.woff?sha=3114f1256") format("woff");font-weight:400;font-style:normal}@font-face{font-family:'Hack';src:url("fonts/hack-bold.woff2?sha=3114f1256") format("woff2"),url("fonts/hack-bold.woff?sha=3114f1256") format("woff");font-weight:700;font-style:normal}@font-face{font-family:'Hack';src:url("fonts/hack-italic.woff2?sha=3114f1256") format("woff2"),url("fonts/hack-italic.woff?sha=3114f1256") format("woff");font-weight:400;font-style:italic}@font-face{font-family:'Hack';src:url("fonts/hack-bolditalic.woff2?sha=3114f1256") format("woff2"),url("fonts/hack-bolditalic.woff?sha=3114f1256") format("woff");font-weight:700;font-style:italic}
*/@font-face{font-family:"Hack";src:url("fonts/hack-regular.woff2?sha=3114f1256") format("woff2"),url("fonts/hack-regular.woff?sha=3114f1256") format("woff");font-weight:400;font-style:normal}@font-face{font-family:"Hack";src:url("fonts/hack-bold.woff2?sha=3114f1256") format("woff2"),url("fonts/hack-bold.woff?sha=3114f1256") format("woff");font-weight:700;font-style:normal}@font-face{font-family:"Hack";src:url("fonts/hack-italic.woff2?sha=3114f1256") format("woff2"),url("fonts/hack-italic.woff?sha=3114f1256") format("woff");font-weight:400;font-style:italic}@font-face{font-family:"Hack";src:url("fonts/hack-bolditalic.woff2?sha=3114f1256") format("woff2"),url("fonts/hack-bolditalic.woff?sha=3114f1256") format("woff");font-weight:700;font-style:italic}

View file

@ -1 +1 @@
.footer{padding:40px 0;flex-grow:0;opacity:.5}.footer__inner{display:flex;align-items:center;justify-content:space-between;margin:0;width:760px;max-width:100%}@media (max-width: 899px){.footer__inner{flex-direction:column}}.footer a{color:inherit}.footer .copyright{display:flex;flex-direction:row;align-items:center;font-size:1rem;color:var(--light-color-secondary)}.footer .copyright--user{margin:auto;text-align:center}.footer .copyright>*:first-child:not(:only-child){margin-right:10px}@media (max-width: 899px){.footer .copyright>*:first-child:not(:only-child){border:none;padding:0;margin:0}}@media (max-width: 899px){.footer .copyright{flex-direction:column;margin-top:10px}}@media (max-width: 899px){.footer .copyright-theme-sep{display:none}}@media (max-width: 899px){.footer .copyright-theme{font-size:0.75rem}}
.footer{padding:40px 0;flex-grow:0;opacity:.5}.footer__inner{display:flex;align-items:center;justify-content:space-between;margin:0;width:760px;max-width:100%}@media (max-width: 899px){.footer__inner{flex-direction:column}}.footer a{color:inherit}.footer .copyright{display:flex;flex-direction:row;align-items:center;font-size:1rem;color:var(--light-color-secondary)}.footer .copyright--user{margin:auto;text-align:center}.footer .copyright>*:first-child:not(:only-child){margin-right:10px}@media (max-width: 899px){.footer .copyright>*:first-child:not(:only-child){border:none;padding:0;margin:0}}@media (max-width: 899px){.footer .copyright{flex-direction:column;margin-top:10px}}@media (max-width: 899px){.footer .copyright-theme-sep{display:none}}@media (max-width: 899px){.footer .copyright-theme{font-size:.75rem}}

View file

@ -1 +1 @@
.header{display:flex;flex-direction:column;position:relative}.header__inner{display:flex;align-items:center;justify-content:space-between}.header__logo{display:flex;flex:1}.header__logo:after{content:'';background:repeating-linear-gradient(90deg, var(--accent), var(--accent) 2px, transparent 0, transparent 16px, var(--accent2), var(--accent2) 17px, transparent 0, transparent 32px);display:block;width:100%;right:10px}.header__logo a{flex:0 0 auto;max-width:100%}.header .menu{margin:20px 0}.header .menu__inner{display:flex;flex-wrap:wrap;list-style:none;margin:0;padding:0}.header .menu__inner li{color:var(--accent3)}.header .menu__inner li.active{color:var(--accent-alpha-70)}.header .menu__inner li:not(:last-of-type){margin-right:20px;margin-bottom:10px;flex:0 0 auto}.header .menu__sub-inner{position:relative;list-style:none;padding:0;margin:0}.header .menu__sub-inner:not(:only-child){margin-left:20px}.header .menu__sub-inner-more{position:absolute;background:var(--background);box-shadow:var(--shadow);color:white;border:2px solid;margin:0;padding:10px;list-style:none;z-index:99;top:35px;left:0}.header .menu__sub-inner-more-trigger{color:var(--accent);user-select:none;cursor:pointer}.header .menu__sub-inner-more li{margin:0;padding:5px;white-space:nowrap}
.header{display:flex;flex-direction:column;position:relative}.header__inner{display:flex;align-items:center;justify-content:space-between}.header__logo{display:flex;flex:1}.header__logo:after{content:"";background:repeating-linear-gradient(90deg, var(--accent), var(--accent) 2px, rgba(0,0,0,0) 0, rgba(0,0,0,0) 16px, var(--accent2), var(--accent2) 17px, rgba(0,0,0,0) 0, rgba(0,0,0,0) 32px);display:block;width:100%;right:10px}.header__logo a{flex:0 0 auto;max-width:100%}.header .menu{margin:20px 0}.header .menu__inner{display:flex;flex-wrap:wrap;list-style:none;margin:0;padding:0}.header .menu__inner li{color:var(--accent3)}.header .menu__inner li.active{color:var(--accent-alpha-70)}.header .menu__inner li:not(:last-of-type){margin-right:20px;margin-bottom:10px;flex:0 0 auto}.header .menu__sub-inner{position:relative;list-style:none;padding:0;margin:0}.header .menu__sub-inner:not(:only-child){margin-left:20px}.header .menu__sub-inner-more{position:absolute;background:var(--background);box-shadow:var(--shadow);color:#fff;border:2px solid;margin:0;padding:10px;list-style:none;z-index:99;top:35px;left:0}.header .menu__sub-inner-more-trigger{color:var(--accent);user-select:none;cursor:pointer}.header .menu__sub-inner-more li{margin:0;padding:5px;white-space:nowrap}

View file

@ -57,7 +57,7 @@
<div class="post">
<h1 class="post-title"><a href="https://cherrykitten.dev/content/">Hello there!</a></h1>
<h1 class="post-title"><a href="https://cherrykitten.dev/home/">Hello there!</a></h1>
<div class="post-meta-inline">
<span class="post-date"></span>
@ -96,7 +96,12 @@
<footer class="footer">
<div class="footer__inner">
<div class="copyright copyright--user"><p>&copy; {currentYear} - CherryKitten</p><a href="/impressum">Impressum</a>
<div class="copyright copyright--user"><p>&copy; 2023 - CherryKitten</p><br>
<p><a href="/impressum">Impressum</a></p>
 
<p><a href="/rss.xml">RSS</a></p>
 
🐱
</div>
</div>
</footer>

View file

@ -89,7 +89,12 @@
<footer class="footer">
<div class="footer__inner">
<div class="copyright copyright--user"><p>&copy; {currentYear} - CherryKitten</p><a href="/impressum">Impressum</a>
<div class="copyright copyright--user"><p>&copy; 2023 - CherryKitten</p><br>
<p><a href="/impressum">Impressum</a></p>
 
<p><a href="/rss.xml">RSS</a></p>
 
🐱
</div>
</div>
</footer>

View file

@ -58,7 +58,7 @@
<div class="posts">
<div class="post on-list">
<h1 class="post-title"><a href="https://cherrykitten.dev/content/">Hello there!</a></h1>
<h1 class="post-title"><a href="https://cherrykitten.dev/home/">Hello there!</a></h1>
<div class="post-meta-inline">
<span class="post-date"></span>
@ -100,7 +100,12 @@
<footer class="footer">
<div class="footer__inner">
<div class="copyright copyright--user"><p>&copy; {currentYear} - CherryKitten</p><a href="/impressum">Impressum</a>
<div class="copyright copyright--user"><p>&copy; 2023 - CherryKitten</p><br>
<p><a href="/impressum">Impressum</a></p>
 
<p><a href="/rss.xml">RSS</a></p>
 
🐱
</div>
</div>
</footer>

View file

@ -1 +1 @@
.logo{display:flex;align-items:center;text-decoration:none;background:var(--accent);color:black;padding:5px 10px}
.logo{display:flex;align-items:center;text-decoration:none;background:var(--accent);color:#000;padding:5px 10px}

View file

@ -1 +1 @@
html{box-sizing:border-box}*,*:before,*:after{box-sizing:inherit}body{margin:0;padding:0;font-family:Hack, DejaVu Sans Mono, Monaco, Consolas, Ubuntu Mono, monospace;font-size:1rem;line-height:1.54;background-color:var(--background);color:var(--color);text-rendering:optimizeLegibility;-webkit-font-smoothing:antialiased;-webkit-overflow-scrolling:touch;-webkit-text-size-adjust:100%}@media (max-width: 683px){body{font-size:1rem}}h1,h2,h3,h4,h5,h6{display:flex;align-items:center;font-weight:bold;line-height:1.3;color:var(--accent2)}h1{font-size:1.4rem}h2{font-size:1.3rem}h3{font-size:1.2rem}h4,h5,h6{font-size:1.15rem}a{color:inherit}img{display:block;max-width:100%}img.left{margin-right:auto}img.center{margin-left:auto;margin-right:auto}img.right{margin-left:auto}p{margin-bottom:20px}figure{display:table;max-width:100%;margin:25px 0}figure.left img{margin-right:auto}figure.center img{margin-left:auto;margin-right:auto}figure.right img{margin-left:auto}figure figcaption{font-size:14px;padding:5px 10px;margin-top:5px;background:var(--accent);color:var(--background)}figure figcaption.left{text-align:left}figure figcaption.center{text-align:center}figure figcaption.right{text-align:right}code{font-family:Hack, DejaVu Sans Mono, Monaco, Consolas, Ubuntu Mono, monospace;font-feature-settings:normal;background:var(--accent-alpha-20);padding:1px 6px;margin:0 2px;font-size:.95rem}pre{font-family:Hack, DejaVu Sans Mono, Monaco, Consolas, Ubuntu Mono, monospace;padding:20px;font-size:.95rem;overflow:auto;border-top:1px solid rgba(255,255,255,0.1);border-bottom:1px solid rgba(255,255,255,0.1)}@media (max-width: 683px){pre{white-space:pre-wrap;word-wrap:break-word}}pre code{padding:0;margin:0;background:none}blockquote{border-top:1px solid var(--accent);border-bottom:1px solid var(--accent);margin:40px 0;padding:25px}@media (max-width: 683px){blockquote{padding-right:0}}blockquote:before{content:'”';font-family:Georgia, serif;font-size:3.875rem;position:absolute;left:-40px;top:-20px}blockquote p:first-of-type{margin-top:0}blockquote p:last-of-type{margin-bottom:0}blockquote p{position:relative}blockquote p:before{content:'>';display:block;position:absolute;left:-25px;color:var(--accent)}table{table-layout:fixed;border-collapse:collapse;width:100%;margin:40px 0}table,th,td{border:1px dashed var(--accent);padding:10px}th{color:var(--accent)}ul,ol{margin-left:30px;padding:0}ul li,ol li{position:relative}@media (max-width: 683px){ul,ol{margin-left:20px}}ol ol{list-style-type:lower-alpha}.container{display:flex;flex-direction:column;padding:40px;max-width:864px;min-height:100vh;margin:0 auto}@media (max-width: 683px){.container{padding:20px}}.content{display:flex}hr{width:100%;border:none;background:var(--border-color);height:1px}.hidden{display:none}
html{box-sizing:border-box}*,*:before,*:after{box-sizing:inherit}body{margin:0;padding:0;font-family:Hack,DejaVu Sans Mono,Monaco,Consolas,Ubuntu Mono,monospace;font-size:1rem;line-height:1.54;background-color:var(--background);color:var(--color);text-rendering:optimizeLegibility;-webkit-font-smoothing:antialiased;-webkit-overflow-scrolling:touch;-webkit-text-size-adjust:100%}@media (max-width: 683px){body{font-size:1rem}}h1,h2,h3,h4,h5,h6{display:flex;align-items:center;font-weight:bold;line-height:1.3;color:var(--accent2)}h1{font-size:1.4rem}h2{font-size:1.3rem}h3{font-size:1.2rem}h4,h5,h6{font-size:1.15rem}a{color:inherit}img{display:block;max-width:100%}img.left{margin-right:auto}img.center{margin-left:auto;margin-right:auto}img.right{margin-left:auto}p{margin-bottom:20px}figure{display:table;max-width:100%;margin:25px 0}figure.left img{margin-right:auto}figure.center img{margin-left:auto;margin-right:auto}figure.right img{margin-left:auto}figure figcaption{font-size:14px;padding:5px 10px;margin-top:5px;background:var(--accent);color:var(--background)}figure figcaption.left{text-align:left}figure figcaption.center{text-align:center}figure figcaption.right{text-align:right}code{font-family:Hack,DejaVu Sans Mono,Monaco,Consolas,Ubuntu Mono,monospace;font-feature-settings:normal;background:var(--accent-alpha-20);padding:1px 6px;margin:0 2px;font-size:.95rem}pre{font-family:Hack,DejaVu Sans Mono,Monaco,Consolas,Ubuntu Mono,monospace;padding:20px;font-size:.95rem;overflow:auto;border-top:1px solid rgba(255,255,255,.1);border-bottom:1px solid rgba(255,255,255,.1)}@media (max-width: 683px){pre{white-space:pre-wrap;word-wrap:break-word}}pre code{padding:0;margin:0;background:none}blockquote{border-top:1px solid var(--accent);border-bottom:1px solid var(--accent);margin:40px 0;padding:25px}@media (max-width: 683px){blockquote{padding-right:0}}blockquote:before{content:"”";font-family:Georgia,serif;font-size:3.875rem;position:absolute;left:-40px;top:-20px}blockquote p:first-of-type{margin-top:0}blockquote p:last-of-type{margin-bottom:0}blockquote p{position:relative}blockquote p:before{content:">";display:block;position:absolute;left:-25px;color:var(--accent)}table{table-layout:fixed;border-collapse:collapse;width:100%;margin:40px 0}table,th,td{border:1px dashed var(--accent);padding:10px}th{color:var(--accent)}ul,ol{margin-left:30px;padding:0}ul li,ol li{position:relative}@media (max-width: 683px){ul,ol{margin-left:20px}}ol ol{list-style-type:lower-alpha}.container{display:flex;flex-direction:column;padding:40px;max-width:864px;min-height:100vh;margin:0 auto}@media (max-width: 683px){.container{padding:20px}}.content{display:flex}hr{width:100%;border:none;background:var(--border-color);height:1px}.hidden{display:none}

View file

@ -1 +1 @@
.pagination{margin-top:50px}.pagination__title{display:flex;text-align:center;position:relative;margin:100px 0 20px}.pagination__title-h{text-align:center;margin:0 auto;padding:5px 10px;background:var(--background);font-size:.8rem;text-transform:uppercase;letter-spacing:.1em;z-index:1}.pagination__title hr{position:absolute;left:0;right:0;width:100%;margin-top:15px;z-index:0}.pagination__buttons{display:flex;align-items:center;justify-content:center}@media (max-width: 683px){.pagination__buttons{flex-direction:column}}.button{position:relative;display:inline-flex;align-items:center;justify-content:center;font-size:1rem;border-radius:8px;max-width:40%;padding:0;cursor:pointer;appearance:none}@media (max-width: 683px){.button{max-width:80%}}.button+.button{margin-left:10px}.button a{display:flex;padding:8px 16px;text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.button__text{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}
.pagination{margin-top:50px}.pagination__title{display:flex;text-align:center;position:relative;margin:100px 0 20px}.pagination__title-h{text-align:center;margin:0 auto;padding:5px 10px;background:var(--background);font-size:.8rem;text-transform:uppercase;letter-spacing:.1em;z-index:1}.pagination__title hr{position:absolute;left:0;right:0;width:100%;margin-top:15px;z-index:0}.pagination__buttons{display:flex;align-items:center;justify-content:center}@media (max-width: 683px){.pagination__buttons{flex-direction:column}}.button{position:relative;display:inline-flex;align-items:center;justify-content:center;font-size:1rem;border-radius:8px;max-width:40%;padding:0;cursor:pointer;appearance:none}@media (max-width: 683px){.button{max-width:80%}}.button+.button{margin-left:10px}.button a{display:flex;padding:8px 16px;text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.button__text{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}

View file

@ -1 +1 @@
.posts{width:100%;margin:0 auto}.post{width:100%;text-align:left;margin:20px auto;padding:20px 0}@media (max-width: 899px){.post{max-width:660px}}.post:not(:last-of-type){border-bottom:1px solid var(--border-color)}.post .post-meta-inline,.post .post-meta{font-size:1rem;margin-bottom:10px;color:var(--accent-alpha-70)}.post-meta-inline{display:inline}.post-title{--border: 2px dashed var(--accent);position:relative;color:var(--accent2);margin:0 0 15px;padding-bottom:15px;border-bottom:var(--border);font-weight:normal}.post-title a{text-decoration:none}.post .post-tags-inline,.post .post-tags{margin-bottom:20px;font-size:1rem;opacity:.5}.post-tags{display:block}.post-tags-inline{display:inline}@media (max-width: 683px){.post-tags-inline{display:block}}.post-content{margin-top:30px}.post-cover{border:20px solid var(--accent);background:transparent;margin:40px 0;padding:20px}@media (max-width: 683px){.post-cover{padding:10px;border-width:10px}}.post ul{list-style:none}.post ul li:before{content:'►';position:absolute;left:-20px;color:var(--accent)}.post--regulation h1{justify-content:center}.post--regulation h2{justify-content:center;margin-bottom:10px}.post--regulation h2+h2{margin-top:-10px;margin-bottom:20px}.post-list .post-date{color:var(--accent3);text-decoration:none}.post-list a{text-decoration:none}.post-list .post-list-title{text-decoration:underline}.post-list .post-tag{text-decoration:underline}
.posts{width:100%;margin:0 auto}.post{width:100%;text-align:left;margin:20px auto;padding:20px 0}@media (max-width: 899px){.post{max-width:660px}}.post:not(:last-of-type){border-bottom:1px solid var(--border-color)}.post .post-meta-inline,.post .post-meta{font-size:1rem;margin-bottom:10px;color:var(--accent-alpha-70)}.post-meta-inline{display:inline}.post-title{--border: 2px dashed var(--accent);position:relative;color:var(--accent2);margin:0 0 15px;padding-bottom:15px;border-bottom:var(--border);font-weight:normal}.post-title a{text-decoration:none}.post .post-tags-inline,.post .post-tags{margin-bottom:20px;font-size:1rem;opacity:.5}.post-tags{display:block}.post-tags-inline{display:inline}@media (max-width: 683px){.post-tags-inline{display:block}}.post-content{margin-top:30px}.post-cover{border:20px solid var(--accent);background:rgba(0,0,0,0);margin:40px 0;padding:20px}@media (max-width: 683px){.post-cover{padding:10px;border-width:10px}}.post ul{list-style:none}.post ul li:before{content:"►";position:absolute;left:-20px;color:var(--accent)}.post--regulation h1{justify-content:center}.post--regulation h2{justify-content:center;margin-bottom:10px}.post--regulation h2+h2{margin-top:-10px;margin-bottom:20px}.post-list .post-date{color:var(--accent3);text-decoration:none}.post-list a{text-decoration:none}.post-list .post-list-title{text-decoration:underline}.post-list .post-tag{text-decoration:underline}

View file

@ -2,21 +2,48 @@
<rss xmlns:atom="http://www.w3.org/2005/Atom" version="2.0">
<channel>
<title>CherryKitten</title>
<link>https://cherrykitten.dev</link>
<description></description>
<generator>Zola</generator>
<language>en</language>
<atom:link href="https://cherrykitten.dev/rss.xml" rel="self" type="application/rss+xml"/>
<lastBuildDate>Sat, 26 Nov 2022 00:00:00 +0000</lastBuildDate>
<item>
<title>The Fediverse is more than just Mastodon</title>
<pubDate>Sat, 26 Nov 2022 00:00:00 +0000</pubDate>
<link>https://cherrykitten.dev/blog/fediverse-isnt-just-mastodon/</link>
<guid>https://cherrykitten.dev/blog/fediverse-isnt-just-mastodon/</guid>
<description>&lt;p&gt;With Twitter in a downwards spiral thanks to some rich guy whose name escapes me breaking everything, the Fediverse has been getting the biggest influx of new users in a very long time.
<link>https://cherrykitten.dev</link>
<description></description>
<generator>Zola</generator>
<language>en</language>
<atom:link href="https://cherrykitten.dev/rss.xml" rel="self" type="application/rss+xml"/>
<lastBuildDate>Sat, 25 Feb 2023 00:00:00 +0000</lastBuildDate>
<item>
<title>Learning Rust Part 1: A kitten&#x27;s guide to Options and Results</title>
<pubDate>Sat, 25 Feb 2023 00:00:00 +0000</pubDate>
<author>Unknown</author>
<link>https://cherrykitten.dev/blog/rust-1-options-results/</link>
<guid>https://cherrykitten.dev/blog/rust-1-options-results/</guid>
<description>&lt;h3 id=&quot;to-unwrap-or-not-to-unwrap-that-is-the-question&quot;&gt;To unwrap() or not to unwrap(), that is the question:&lt;&#x2F;h3&gt;
&lt;p&gt;So I&#x27;ve finally given in and started to learn Rust last month. It&#x27;s a really cool programming language,
with some interesting differences to what I&#x27;ve used before. (JavaScript and Python, mostly)&lt;&#x2F;p&gt;
&lt;p&gt;There are some really pawesome guides out there, &lt;a href=&quot;https:&#x2F;&#x2F;doc.rust-lang.org&#x2F;book&#x2F;&quot;&gt;&amp;quot;The Rust programming language&amp;quot;&lt;&#x2F;a&gt; is
definitely a &lt;strong&gt;must-read&lt;&#x2F;strong&gt; in my opinion, and &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;rust-lang&#x2F;rustlings&quot;&gt;Rustlings&lt;&#x2F;a&gt; is nyamazing for
anyone who likes to learn by actively working through interactive problems.&lt;&#x2F;p&gt;
&lt;p&gt;After reading through a lot of those big thorough guides by experienced Rust developers, I&#x27;ve started working on
my first actual Project. I approached the development of this project by just trying to get small parts of it
working in any way I can manage, and then build upon this. In that process, I learned a lot of small subtilties that
guides like the ones named above just can&#x27;t really cover. This post is for sharing those things, those cool little
tips to make your first Rust project just a little cleaner and more Rust-y. Originally I wanted to make this about a lot
of different topics, but then I&#x27;ve realized that my notes already contain so many things about just one part of Rust:
The Enums &lt;code&gt;Option&lt;&#x2F;code&gt; and &lt;code&gt;Result&lt;&#x2F;code&gt;. So this post will be about those, and hopefully will mark the start of a series on this blog.&lt;&#x2F;p&gt;
&lt;p&gt;While reading through this, you might think that the things I&#x27;m mentioning are obvious. That&#x27;s okay, and that&#x27;s the point.
Nothing is ever completely obvious to everyone, and this is for those like me, who often don&#x27;t immediately recognize
the &amp;quot;obvious&amp;quot;. And, to be honest, I am writing this just as much for myself, writing all of that stuff down to aid me in my
own ongoing learning process.&lt;&#x2F;p&gt;
&lt;p&gt;So, let&#x27;s start!&lt;&#x2F;p&gt;
</description>
</item>
<item>
<title>The Fediverse is more than just Mastodon</title>
<pubDate>Sat, 26 Nov 2022 00:00:00 +0000</pubDate>
<author>Unknown</author>
<link>https://cherrykitten.dev/blog/fediverse-isnt-just-mastodon/</link>
<guid>https://cherrykitten.dev/blog/fediverse-isnt-just-mastodon/</guid>
<description>&lt;p&gt;With Twitter in a downwards spiral thanks to some rich guy whose name escapes me breaking everything, the Fediverse has been getting the biggest influx of new users in a very long time.
People have been recommending &amp;quot;Mastodon&amp;quot; as a Twitter alternative for a while now, causing #Mastodon to be the top trending Hashtag on many days.&lt;&#x2F;p&gt;
&lt;p&gt;Browsing that hashtag one can find a lot of misconceptions about what Mastodon is, how it works, and what its limitations are. These misconceptions are not just spread by people who dislike Mastodon and try to convince others not to use it, though. They are also perpetuated by people who seem to want to increase the userbase at all cost, regardless of whom it attracts to the Fediverse.&lt;&#x2F;p&gt;
</description>
</item>
</item>
</channel>
</rss>

View file

@ -16,11 +16,15 @@
<url>
<loc>https://cherrykitten.dev/blog/page/1/</loc>
</url>
<url>
<loc>https://cherrykitten.dev/blog/rust-1-options-results/</loc>
<lastmod>2023-02-25</lastmod>
</url>
<url>
<loc>https://cherrykitten.dev/contact/</loc>
</url>
<url>
<loc>https://cherrykitten.dev/content/</loc>
<loc>https://cherrykitten.dev/home/</loc>
</url>
<url>
<loc>https://cherrykitten.dev/impressum/</loc>
@ -34,13 +38,25 @@
<url>
<loc>https://cherrykitten.dev/tags/calckey/</loc>
</url>
<url>
<loc>https://cherrykitten.dev/tags/code/</loc>
</url>
<url>
<loc>https://cherrykitten.dev/tags/fediverse/</loc>
</url>
<url>
<loc>https://cherrykitten.dev/tags/learning/</loc>
</url>
<url>
<loc>https://cherrykitten.dev/tags/mastodon/</loc>
</url>
<url>
<loc>https://cherrykitten.dev/tags/misskey/</loc>
</url>
<url>
<loc>https://cherrykitten.dev/tags/programming/</loc>
</url>
<url>
<loc>https://cherrykitten.dev/tags/rust/</loc>
</url>
</urlset>

File diff suppressed because one or more lines are too long