mirror of
				https://github.com/bspeice/speice.io
				synced 2025-10-31 09:30:32 -04:00 
			
		
		
		
	Base formatting
This commit is contained in:
		
							
								
								
									
										787
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										787
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @ -10,6 +10,10 @@ | |||||||
|     "prepare": "husky install" |     "prepare": "husky install" | ||||||
|   }, |   }, | ||||||
|   "dependencies": { |   "dependencies": { | ||||||
|  |     "@fontsource/jetbrains-mono": "^4.5.12", | ||||||
|  |     "@fontsource/lato": "^4.5.10", | ||||||
|  |     "normalize.css": "^8.0.1", | ||||||
|  |     "prism-themes": "^1.9.0", | ||||||
|     "react": "^18.2.0", |     "react": "^18.2.0", | ||||||
|     "react-dom": "^18.2.0" |     "react-dom": "^18.2.0" | ||||||
|   }, |   }, | ||||||
| @ -18,9 +22,11 @@ | |||||||
|     "@mdx-js/rollup": "^2.3.0", |     "@mdx-js/rollup": "^2.3.0", | ||||||
|     "@types/react": "^18.0.28", |     "@types/react": "^18.0.28", | ||||||
|     "@types/react-dom": "^18.0.11", |     "@types/react-dom": "^18.0.11", | ||||||
|  |     "@types/remark-prism": "^1.3.4", | ||||||
|     "@vitejs/plugin-react-swc": "^3.0.0", |     "@vitejs/plugin-react-swc": "^3.0.0", | ||||||
|     "husky": "^8.0.0", |     "husky": "^8.0.0", | ||||||
|     "pretty-quick": "^3.1.3", |     "pretty-quick": "^3.1.3", | ||||||
|  |     "remark-prism": "^1.3.6", | ||||||
|     "typescript": "^4.9.3", |     "typescript": "^4.9.3", | ||||||
|     "vite": "^4.2.0" |     "vite": "^4.2.0" | ||||||
|   } |   } | ||||||
|  | |||||||
							
								
								
									
										20
									
								
								pages/LayoutBase.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								pages/LayoutBase.tsx
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,20 @@ | |||||||
|  | import { PropsWithChildren } from "react"; | ||||||
|  |  | ||||||
|  | import "./style.css"; | ||||||
|  |  | ||||||
|  | const Sidebar: React.FC = () => ( | ||||||
|  |   <span className={"navbar"}> | ||||||
|  |     <a href="/">Home</a>/<a href="/about">About</a> | ||||||
|  |   </span> | ||||||
|  | ); | ||||||
|  |  | ||||||
|  | const Layout: React.FC<PropsWithChildren> = ({ children }) => ( | ||||||
|  |   <div className="gridOffset"> | ||||||
|  |     <div className="gridOffsetSide"> | ||||||
|  |       <Sidebar /> | ||||||
|  |     </div> | ||||||
|  |     {children} | ||||||
|  |   </div> | ||||||
|  | ); | ||||||
|  |  | ||||||
|  | export default Layout; | ||||||
							
								
								
									
										12
									
								
								pages/LayoutPage.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								pages/LayoutPage.tsx
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,12 @@ | |||||||
|  | import { PropsWithChildren } from "react"; | ||||||
|  |  | ||||||
|  | import Base from "./LayoutBase"; | ||||||
|  |  | ||||||
|  | const Layout: React.FC<PropsWithChildren> = ({ children }) => ( | ||||||
|  |   <Base> | ||||||
|  |     <h1>The Old Speice Guy</h1> | ||||||
|  |     {children} | ||||||
|  |   </Base> | ||||||
|  | ); | ||||||
|  |  | ||||||
|  | export default Layout; | ||||||
							
								
								
									
										8
									
								
								pages/about.mdx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								pages/about.mdx
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,8 @@ | |||||||
|  | import Layout from "./Page"; | ||||||
|  | export default Layout; | ||||||
|  |  | ||||||
|  | Developer currently living in New York City | ||||||
|  |  | ||||||
|  | Email: [bradlee@speice.io](mailto:bradlee@speice.io) | ||||||
|  |  | ||||||
|  | LinkedIn: [bradleespeice](https://www.linkedin.com/in/bradleespeice/) | ||||||
| @ -1,9 +1,9 @@ | |||||||
| import React from "react"; | import Layout from "./LayoutPage"; | ||||||
|  |  | ||||||
| export default function Page() { | export default function () { | ||||||
|   return ( |   return ( | ||||||
|     <> |     <Layout> | ||||||
|       <p>Is this thing on?</p> |       <p>Is this thing on?</p> | ||||||
|     </> |     </Layout> | ||||||
|   ); |   ); | ||||||
| } | } | ||||||
|  | |||||||
							
								
								
									
										72
									
								
								pages/style.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								pages/style.css
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,72 @@ | |||||||
|  | @import "normalize.css"; | ||||||
|  |  | ||||||
|  | @import "@fontsource/lato"; | ||||||
|  | @import "@fontsource/jetbrains-mono"; | ||||||
|  | @import "prism-themes/themes/prism-material-dark"; | ||||||
|  |  | ||||||
|  | body { | ||||||
|  |   font-family: "Lato", sans-serif; | ||||||
|  |   font-size: 14pt; | ||||||
|  |   line-height: 1.4; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | h1, | ||||||
|  | h2, | ||||||
|  | h3, | ||||||
|  | h4, | ||||||
|  | h5, | ||||||
|  | h6 { | ||||||
|  |   margin-top: 0.6em; | ||||||
|  |   margin-bottom: 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | p, | ||||||
|  | ul { | ||||||
|  |   margin-top: 0.5em; | ||||||
|  |   margin-bottom: 0.5em; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | pre { | ||||||
|  |   padding: 1em 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | code, | ||||||
|  | code[class*="language-"] { | ||||||
|  |   font-family: "JetBrains Mono", monospace; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | .gridOffset { | ||||||
|  |   display: grid; | ||||||
|  |   grid-template-columns: | ||||||
|  |     [full-start] minmax(1em, 2fr) | ||||||
|  |     [main-start] minmax(0, 45em) [main-end] | ||||||
|  |     minmax(0, 1fr) | ||||||
|  |     [side-start] minmax(0, 3fr) [side-end] | ||||||
|  |     minmax(1em, 2fr) [full-end]; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | .gridOffset > :not(.gridOffsetSide) { | ||||||
|  |   grid-column: main; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | .gridOffset > div.remark-highlight, | ||||||
|  | .gridOffset > div.remark-highlight > pre { | ||||||
|  |   display: inherit; | ||||||
|  |   grid-column: full; | ||||||
|  |   grid-template-columns: inherit; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | .gridOffset > div.remark-highlight > pre > code { | ||||||
|  |   grid-column: main; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | .gridOffsetSide { | ||||||
|  |   grid-column: side; | ||||||
|  |   margin-top: 1em; | ||||||
|  |   margin-bottom: 1em; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | .navbar > * { | ||||||
|  |   margin-left: 0.5em; | ||||||
|  |   margin-right: 0.5em; | ||||||
|  | } | ||||||
							
								
								
									
										336
									
								
								posts/2019/02/the-whole-world.mdx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										336
									
								
								posts/2019/02/the-whole-world.mdx
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,336 @@ | |||||||
|  | import Blog from "../../LayoutBlog"; | ||||||
|  | export default Blog({ | ||||||
|  |   title: "Global Memory Usage: The Whole World", | ||||||
|  |   description: "Static considered slightly less harmful.", | ||||||
|  |   published: "2019-02-05", | ||||||
|  | }); | ||||||
|  |  | ||||||
|  | The first memory type we'll look at is pretty special: when Rust can prove that a _value_ is fixed | ||||||
|  | for the life of a program (`const`), and when a _reference_ is unique for the life of a program | ||||||
|  | (`static` as a declaration, not | ||||||
|  | [`'static`](https://doc.rust-lang.org/book/ch10-03-lifetime-syntax.html#the-static-lifetime) as a | ||||||
|  | lifetime), we can make use of global memory. This special section of data is embedded directly in | ||||||
|  | the program binary so that variables are ready to go once the program loads; no additional | ||||||
|  | computation is necessary. | ||||||
|  |  | ||||||
|  | Understanding the value/reference distinction is important for reasons we'll go into below, and | ||||||
|  | while the | ||||||
|  | [full specification](https://github.com/rust-lang/rfcs/blob/master/text/0246-const-vs-static.md) for | ||||||
|  | these two keywords is available, we'll take a hands-on approach to the topic. | ||||||
|  |  | ||||||
|  | # **const** | ||||||
|  |  | ||||||
|  | When a _value_ is guaranteed to be unchanging in your program (where "value" may be scalars, | ||||||
|  | `struct`s, etc.), you can declare it `const`. This tells the compiler that it's safe to treat the | ||||||
|  | value as never changing, and enables some interesting optimizations; not only is there no | ||||||
|  | initialization cost to creating the value (it is loaded at the same time as the executable parts of | ||||||
|  | your program), but the compiler can also copy the value around if it speeds up the code. | ||||||
|  |  | ||||||
|  | The points we need to address when talking about `const` are: | ||||||
|  |  | ||||||
|  | - `Const` values are stored in read-only memory - it's impossible to modify. | ||||||
|  | - Values resulting from calling a `const fn` are materialized at compile-time. | ||||||
|  | - The compiler may (or may not) copy `const` values wherever it chooses. | ||||||
|  |  | ||||||
|  | ## Read-Only | ||||||
|  |  | ||||||
|  | The first point is a bit strange - "read-only memory." | ||||||
|  | [The Rust book](https://doc.rust-lang.org/book/ch03-01-variables-and-mutability.html#differences-between-variables-and-constants) | ||||||
|  | mentions in a couple places that using `mut` with constants is illegal, but it's also important to | ||||||
|  | demonstrate just how immutable they are. _Typically_ in Rust you can use | ||||||
|  | [interior mutability](https://doc.rust-lang.org/book/ch15-05-interior-mutability.html) to modify | ||||||
|  | things that aren't declared `mut`. | ||||||
|  | [`RefCell`](https://doc.rust-lang.org/std/cell/struct.RefCell.html) provides an example of this | ||||||
|  | pattern in action: | ||||||
|  |  | ||||||
|  | ```rust | ||||||
|  | use std::cell::RefCell; | ||||||
|  |  | ||||||
|  | fn my_mutator(cell: &RefCell<u8>) { | ||||||
|  |     // Even though we're given an immutable reference, | ||||||
|  |     // the `replace` method allows us to modify the inner value. | ||||||
|  |     cell.replace(14); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | fn main() { | ||||||
|  |     let cell = RefCell::new(25); | ||||||
|  |     // Prints out 25 | ||||||
|  |     println!("Cell: {:?}", cell); | ||||||
|  |     my_mutator(&cell); | ||||||
|  |     // Prints out 14 | ||||||
|  |     println!("Cell: {:?}", cell); | ||||||
|  | } | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | -- | ||||||
|  | [Rust Playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=8e4bea1a718edaff4507944e825a54b2) | ||||||
|  |  | ||||||
|  | When `const` is involved though, interior mutability is impossible: | ||||||
|  |  | ||||||
|  | ```rust | ||||||
|  | use std::cell::RefCell; | ||||||
|  |  | ||||||
|  | const CELL: RefCell<u8> = RefCell::new(25); | ||||||
|  |  | ||||||
|  | fn my_mutator(cell: &RefCell<u8>) { | ||||||
|  |     cell.replace(14); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | fn main() { | ||||||
|  |     // First line prints 25 as expected | ||||||
|  |     println!("Cell: {:?}", &CELL); | ||||||
|  |     my_mutator(&CELL); | ||||||
|  |     // Second line *still* prints 25 | ||||||
|  |     println!("Cell: {:?}", &CELL); | ||||||
|  | } | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | -- | ||||||
|  | [Rust Playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=88fe98110c33c1b3a51e341f48b8ae00) | ||||||
|  |  | ||||||
|  | And a second example using [`Once`](https://doc.rust-lang.org/std/sync/struct.Once.html): | ||||||
|  |  | ||||||
|  | ```rust | ||||||
|  | use std::sync::Once; | ||||||
|  |  | ||||||
|  | const SURPRISE: Once = Once::new(); | ||||||
|  |  | ||||||
|  | fn main() { | ||||||
|  |     // This is how `Once` is supposed to be used | ||||||
|  |     SURPRISE.call_once(|| println!("Initializing...")); | ||||||
|  |     // Because `Once` is a `const` value, we never record it | ||||||
|  |     // having been initialized the first time, and this closure | ||||||
|  |     // will also execute. | ||||||
|  |     SURPRISE.call_once(|| println!("Initializing again???")); | ||||||
|  | } | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | -- | ||||||
|  | [Rust Playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=c3cc5979b5e5434eca0f9ec4a06ee0ed) | ||||||
|  |  | ||||||
|  | When the | ||||||
|  | [`const` specification](https://github.com/rust-lang/rfcs/blob/26197104b7bb9a5a35db243d639aee6e46d35d75/text/0246-const-vs-static.md) | ||||||
|  | refers to ["rvalues"](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3055.pdf), this | ||||||
|  | behavior is what they refer to. [Clippy](https://github.com/rust-lang/rust-clippy) will treat this | ||||||
|  | as an error, but it's still something to be aware of. | ||||||
|  |  | ||||||
|  | ## Initialization == Compilation | ||||||
|  |  | ||||||
|  | The next thing to mention is that `const` values are loaded into memory _as part of your program | ||||||
|  | binary_. Because of this, any `const` values declared in your program will be "realized" at | ||||||
|  | compile-time; accessing them may trigger a main-memory lookup (with a fixed address, so your CPU may | ||||||
|  | be able to prefetch the value), but that's it. | ||||||
|  |  | ||||||
|  | ```rust | ||||||
|  | use std::cell::RefCell; | ||||||
|  |  | ||||||
|  | const CELL: RefCell<u32> = RefCell::new(24); | ||||||
|  |  | ||||||
|  | pub fn multiply(value: u32) -> u32 { | ||||||
|  |     // CELL is stored at `.L__unnamed_1` | ||||||
|  |     value * (*CELL.get_mut()) | ||||||
|  | } | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | -- [Compiler Explorer](https://godbolt.org/z/Th8boO) | ||||||
|  |  | ||||||
|  | The compiler creates one `RefCell`, uses it everywhere, and never needs to call the `RefCell::new` | ||||||
|  | function. | ||||||
|  |  | ||||||
|  | ## Copying | ||||||
|  |  | ||||||
|  | If it's helpful though, the compiler can choose to copy `const` values. | ||||||
|  |  | ||||||
|  | ```rust | ||||||
|  | const FACTOR: u32 = 1000; | ||||||
|  |  | ||||||
|  | pub fn multiply(value: u32) -> u32 { | ||||||
|  |     // See assembly line 4 for the `mov edi, 1000` instruction | ||||||
|  |     value * FACTOR | ||||||
|  | } | ||||||
|  |  | ||||||
|  | pub fn multiply_twice(value: u32) -> u32 { | ||||||
|  |     // See assembly lines 22 and 29 for `mov edi, 1000` instructions | ||||||
|  |     value * FACTOR * FACTOR | ||||||
|  | } | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | -- [Compiler Explorer](https://godbolt.org/z/ZtS54X) | ||||||
|  |  | ||||||
|  | In this example, the `FACTOR` value is turned into the `mov edi, 1000` instruction in both the | ||||||
|  | `multiply` and `multiply_twice` functions; the "1000" value is never "stored" anywhere, as it's | ||||||
|  | small enough to inline into the assembly instructions. | ||||||
|  |  | ||||||
|  | Finally, getting the address of a `const` value is possible, but not guaranteed to be unique | ||||||
|  | (because the compiler can choose to copy values). I was unable to get non-unique pointers in my | ||||||
|  | testing (even using different crates), but the specifications are clear enough: _don't rely on | ||||||
|  | pointers to `const` values being consistent_. To be frank, caring about locations for `const` values | ||||||
|  | is almost certainly a code smell. | ||||||
|  |  | ||||||
|  | # **static** | ||||||
|  |  | ||||||
|  | Static variables are related to `const` variables, but take a slightly different approach. When we | ||||||
|  | declare that a _reference_ is unique for the life of a program, you have a `static` variable | ||||||
|  | (unrelated to the `'static` lifetime). Because of the reference/value distinction with | ||||||
|  | `const`/`static`, static variables behave much more like typical "global" variables. | ||||||
|  |  | ||||||
|  | But to understand `static`, here's what we'll look at: | ||||||
|  |  | ||||||
|  | - `static` variables are globally unique locations in memory. | ||||||
|  | - Like `const`, `static` variables are loaded at the same time as your program being read into | ||||||
|  |   memory. | ||||||
|  | - All `static` variables must implement the | ||||||
|  |   [`Sync`](https://doc.rust-lang.org/std/marker/trait.Sync.html) marker trait. | ||||||
|  | - Interior mutability is safe and acceptable when using `static` variables. | ||||||
|  |  | ||||||
|  | ## Memory Uniqueness | ||||||
|  |  | ||||||
|  | The single biggest difference between `const` and `static` is the guarantees provided about | ||||||
|  | uniqueness. Where `const` variables may or may not be copied in code, `static` variables are | ||||||
|  | guarantee to be unique. If we take a previous `const` example and change it to `static`, the | ||||||
|  | difference should be clear: | ||||||
|  |  | ||||||
|  | ```rust | ||||||
|  | static FACTOR: u32 = 1000; | ||||||
|  |  | ||||||
|  | pub fn multiply(value: u32) -> u32 { | ||||||
|  |     // The assembly to `mul dword ptr [rip + example::FACTOR]` is how FACTOR gets used | ||||||
|  |     value * FACTOR | ||||||
|  | } | ||||||
|  |  | ||||||
|  | pub fn multiply_twice(value: u32) -> u32 { | ||||||
|  |     // The assembly to `mul dword ptr [rip + example::FACTOR]` is how FACTOR gets used | ||||||
|  |     value * FACTOR * FACTOR | ||||||
|  | } | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | -- [Compiler Explorer](https://godbolt.org/z/uxmiRQ) | ||||||
|  |  | ||||||
|  | Where [previously](#copying) there were plenty of references to multiplying by 1000, the new | ||||||
|  | assembly refers to `FACTOR` as a named memory location instead. No initialization work needs to be | ||||||
|  | done, but the compiler can no longer prove the value never changes during execution. | ||||||
|  |  | ||||||
|  | ## Initialization == Compilation | ||||||
|  |  | ||||||
|  | Next, let's talk about initialization. The simplest case is initializing static variables with | ||||||
|  | either scalar or struct notation: | ||||||
|  |  | ||||||
|  | ```rust | ||||||
|  | #[derive(Debug)] | ||||||
|  | struct MyStruct { | ||||||
|  |     x: u32 | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static MY_STRUCT: MyStruct = MyStruct { | ||||||
|  |     // You can even reference other statics | ||||||
|  |     // declared later | ||||||
|  |     x: MY_VAL | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | static MY_VAL: u32 = 24; | ||||||
|  |  | ||||||
|  | fn main() { | ||||||
|  |     println!("Static MyStruct: {:?}", MY_STRUCT); | ||||||
|  | } | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | -- | ||||||
|  | [Rust Playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=b538dbc46076f12db047af4f4403ee6e) | ||||||
|  |  | ||||||
|  | Things can get a bit weirder when using `const fn` though. In most cases, it just works: | ||||||
|  |  | ||||||
|  | ```rust | ||||||
|  | #[derive(Debug)] | ||||||
|  | struct MyStruct { | ||||||
|  |     x: u32 | ||||||
|  | } | ||||||
|  |  | ||||||
|  | impl MyStruct { | ||||||
|  |     const fn new() -> MyStruct { | ||||||
|  |         MyStruct { x: 24 } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static MY_STRUCT: MyStruct = MyStruct::new(); | ||||||
|  |  | ||||||
|  | fn main() { | ||||||
|  |     println!("const fn Static MyStruct: {:?}", MY_STRUCT); | ||||||
|  | } | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | -- | ||||||
|  | [Rust Playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=8c796a6e7fc273c12115091b707b0255) | ||||||
|  |  | ||||||
|  | However, there's a caveat: you're currently not allowed to use `const fn` to initialize static | ||||||
|  | variables of types that aren't marked `Sync`. For example, | ||||||
|  | [`RefCell::new()`](https://doc.rust-lang.org/std/cell/struct.RefCell.html#method.new) is a | ||||||
|  | `const fn`, but because | ||||||
|  | [`RefCell` isn't `Sync`](https://doc.rust-lang.org/std/cell/struct.RefCell.html#impl-Sync), you'll | ||||||
|  | get an error at compile time: | ||||||
|  |  | ||||||
|  | ```rust | ||||||
|  | use std::cell::RefCell; | ||||||
|  |  | ||||||
|  | // error[E0277]: `std::cell::RefCell<u8>` cannot be shared between threads safely | ||||||
|  | static MY_LOCK: RefCell<u8> = RefCell::new(0); | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | -- | ||||||
|  | [Rust Playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=c76ef86e473d07117a1700e21fd45560) | ||||||
|  |  | ||||||
|  | It's likely that this will | ||||||
|  | [change in the future](https://github.com/rust-lang/rfcs/blob/master/text/0911-const-fn.md) though. | ||||||
|  |  | ||||||
|  | ## **Sync** | ||||||
|  |  | ||||||
|  | Which leads well to the next point: static variable types must implement the | ||||||
|  | [`Sync` marker](https://doc.rust-lang.org/std/marker/trait.Sync.html). Because they're globally | ||||||
|  | unique, it must be safe for you to access static variables from any thread at any time. Most | ||||||
|  | `struct` definitions automatically implement the `Sync` trait because they contain only elements | ||||||
|  | which themselves implement `Sync` (read more in the | ||||||
|  | [Nomicon](https://doc.rust-lang.org/nomicon/send-and-sync.html)). This is why earlier examples could | ||||||
|  | get away with initializing statics, even though we never included an `impl Sync for MyStruct` in the | ||||||
|  | code. To demonstrate this property, Rust refuses to compile our earlier example if we add a | ||||||
|  | non-`Sync` element to the `struct` definition: | ||||||
|  |  | ||||||
|  | ```rust | ||||||
|  | use std::cell::RefCell; | ||||||
|  |  | ||||||
|  | struct MyStruct { | ||||||
|  |     x: u32, | ||||||
|  |     y: RefCell<u8>, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // error[E0277]: `std::cell::RefCell<u8>` cannot be shared between threads safely | ||||||
|  | static MY_STRUCT: MyStruct = MyStruct { | ||||||
|  |     x: 8, | ||||||
|  |     y: RefCell::new(8) | ||||||
|  | }; | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | -- | ||||||
|  | [Rust Playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=40074d0248f056c296b662dbbff97cfc) | ||||||
|  |  | ||||||
|  | ## Interior Mutability | ||||||
|  |  | ||||||
|  | Finally, while `static mut` variables are allowed, mutating them is an `unsafe` operation. If we | ||||||
|  | want to stay in `safe` Rust, we can use interior mutability to accomplish similar goals: | ||||||
|  |  | ||||||
|  | ```rust | ||||||
|  | use std::sync::Once; | ||||||
|  |  | ||||||
|  | // This example adapted from https://doc.rust-lang.org/std/sync/struct.Once.html#method.call_once | ||||||
|  | static INIT: Once = Once::new(); | ||||||
|  |  | ||||||
|  | fn main() { | ||||||
|  |     // Note that while `INIT` is declared immutable, we're still allowed | ||||||
|  |     // to mutate its interior | ||||||
|  |     INIT.call_once(|| println!("Initializing...")); | ||||||
|  |     // This code won't panic, as the interior of INIT was modified | ||||||
|  |     // as part of the previous `call_once` | ||||||
|  |     INIT.call_once(|| panic!("INIT was called twice!")); | ||||||
|  | } | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | -- | ||||||
|  | [Rust Playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=3ba003a981a7ed7400240caadd384d59) | ||||||
							
								
								
									
										35
									
								
								posts/LayoutBlog.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								posts/LayoutBlog.tsx
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,35 @@ | |||||||
|  | import { PropsWithChildren } from "react"; | ||||||
|  |  | ||||||
|  | import Base from "../pages/LayoutBase"; | ||||||
|  |  | ||||||
|  | interface BlogProps { | ||||||
|  |   title: string; | ||||||
|  |   description: string; | ||||||
|  |   published: string; | ||||||
|  |   updated?: string; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export default function Layout({ | ||||||
|  |   title, | ||||||
|  |   description, | ||||||
|  |   published, | ||||||
|  |   updated, | ||||||
|  | }: BlogProps): React.FC<PropsWithChildren> { | ||||||
|  |   const header = ( | ||||||
|  |     <div className="header"> | ||||||
|  |       <h1>{title}</h1> | ||||||
|  |       <h3>{description}</h3> | ||||||
|  |       <p>Published: {published}</p> | ||||||
|  |       {updated && <p>Last updated: {updated}</p>} | ||||||
|  |     </div> | ||||||
|  |   ); | ||||||
|  |  | ||||||
|  |   const withChildren: React.FC<PropsWithChildren> = ({ children }) => ( | ||||||
|  |     <Base> | ||||||
|  |       {header} | ||||||
|  |       <hr /> | ||||||
|  |       {children} | ||||||
|  |     </Base> | ||||||
|  |   ); | ||||||
|  |   return withChildren; | ||||||
|  | } | ||||||
| @ -3,12 +3,16 @@ import blog from "@bspeice/vite-plugin-blog"; | |||||||
| import mdx from "@mdx-js/rollup"; | import mdx from "@mdx-js/rollup"; | ||||||
| import react from "@vitejs/plugin-react-swc"; | import react from "@vitejs/plugin-react-swc"; | ||||||
|  |  | ||||||
|  | import remarkPrism from "remark-prism"; | ||||||
|  |  | ||||||
| export default defineConfig({ | export default defineConfig({ | ||||||
|   plugins: [ |   plugins: [ | ||||||
|     blog({ |     blog({ | ||||||
|       "/": "/pages/index", |       "/": "/pages/index.tsx", | ||||||
|  |       "/about": "/pages/about.mdx", | ||||||
|  |       "/2019/02/the-whole-world": "/posts/2019/02/the-whole-world.mdx", | ||||||
|     }), |     }), | ||||||
|     mdx(), |     mdx({ remarkPlugins: [remarkPrism] }), | ||||||
|     react(), |     react(), | ||||||
|   ], |   ], | ||||||
| }); | }); | ||||||
|  | |||||||
		Reference in New Issue
	
	Block a user