Compare commits

...

5 Commits

  1. 2
      development/libs/atomptr/Cargo.toml
  2. 81
      development/libs/atomptr/src/lib.rs
  3. 13
      infra/libkookie/overlays/kookie/emacs/base/default.el
  4. 1
      infra/libkookie/overlays/kookie/emacs/base/default.nix
  5. 10
      infra/libkookie/overlays/kookie/emacs/builder.nix
  6. 3
      infra/libkookie/overlays/kookie/emacs/default.nix
  7. 14
      infra/libkookie/overlays/kookie/emacs/kookie-notmuch/default.nix
  8. 9
      infra/libkookie/overlays/kookie/emacs/org/default.el
  9. 8
      infra/libkookie/overlays/kookie/emacs/org/default.nix
  10. 3
      infra/libkookie/overlays/kookie/emacs/rust/default.nix
  11. 1
      infra/libkookie/overlays/kookie/emacs/theme/default.el
  12. 1
      prototypes/craftlang/.envrc
  13. 0
      prototypes/craftlang/.projectile
  14. 81
      prototypes/craftlang/README.md
  15. 64
      prototypes/craftlang/craftlangc
  16. 1
      prototypes/craftlang/shell.nix
  17. 6
      prototypes/craftlang/test.cl

@ -1,7 +1,7 @@
[package]
name = "atomptr"
description = "A safe, dependency-less abstraction for typed atomic smart pointers"
version = "1.0.2"
version = "1.1.0"
authors = ["Mx Kookie <kookie@spacekookie.de>"]
edition = "2018"
license = "GPL-3.0-or-later"

@ -1,33 +1,31 @@
//! A safe, strongly typed (generic) atomic pointer abstraction to build
//! datastructures, and lock-free algorithms on top of. Only uses
//! `libstd`.
//!
//! A safe, strongly typed (generic) atomic pointer abstraction to
//! build datastructures, and lock-free algorithms on top of. Only
//! uses `libstd`.
//!
//! The standard library contains an `AtomicPtr` type, which by itself
//! isn't very ergonomic to use, because it deals with raw pointers. This
//! library assumes that types can always be heap allocated, wrapping them
//! in a `Box<T>`, and provides a nicer (and safe!) abstraction for
//! `std::sync::atomic::AtomicPtr`. Using this crate is fairely
//! self-explanatory:
//!
//! isn't very ergonomic to use, because it deals with raw pointers.
//! This library assumes that types can always be heap allocated,
//! wrapping them in a `Box<T>`, and provides a nicer (and safe!)
//! abstraction for `std::sync::atomic::AtomicPtr`. Using this crate
//! is fairely self-explanatory:
//!
//! ```rust
//! use atomptr::AtomPtr;
//!
//!
//! struct MyData { name: String }
//! let data = MyData { name: "Kookie".into() };
//!
//!
//! let a = AtomPtr::new(data);
//! println!("Name is: {}", a.get_ref().name);
//!
//!
//! let old_ref = a.swap(MyData { name: "Bob".into() });
//! println!("Name now is: {}, was {}", a.get_ref().name, old_ref.name);
//! ```
//!
//!
//! Note that the type that is returned by `get_ref` and `swap` is
//! `Ref<T>`, which means that the old data is not de-allocated after a
//! swap, before this last reference goes out of scope. You can of course
//! always manually call `drop()` on it.
//! `Ref<T>`, which means that the old data is not de-allocated after
//! a swap, before this last reference goes out of scope. You can of
//! course always manually call `drop()` on it.
use std::sync::{
atomic::{AtomicPtr, Ordering},
@ -40,6 +38,18 @@ pub struct Ref<T> {
inner: Box<Arc<T>>,
}
impl<T> Ref<T> {
/// Consume this Ref wrapper to yield the underlying `Arc<T>`
///
/// If you want to take ownership of the underlying type data, and
/// you can prove that only one strong-reference Arc exists to
/// this type, you can use `std::arc::Arc::try_unwrap()` to peel
/// the reference counter and take exclusive ownership.
pub fn consume(self) -> Arc<T> {
*self.inner
}
}
impl<T> Deref for Ref<T> {
type Target = Arc<T>;
@ -97,13 +107,8 @@ impl<T> AtomPtr<T> {
let new = Self::make_raw_ptr(new);
let prev = self.inner.swap(new, Ordering::Relaxed);
let b = unsafe { Box::from_raw(prev) };
let arc = Arc::clone(&*b);
std::mem::forget(b);
Ref {
inner: Box::new(arc),
}
let inner = unsafe { Box::from_raw(prev) };
Ref { inner }
}
}
@ -146,3 +151,27 @@ fn swap() {
// But the old ref is still valid
assert_eq!(ts1, *still_ts1.as_ref());
}
#[test]
fn take_from_swap() {
let ts1 = TestStruct {
name: "Hello 1".into(),
};
let ts2 = TestStruct {
name: "Hello 2".into(),
};
// Make an AtomPtr with some data
let ptr = AtomPtr::new(ts1.clone());
assert_eq!(ptr.get_ref().name, "Hello 1".to_string());
// Swap the data
let still_ts1 = ptr.swap(ts2);
assert_eq!(ptr.get_ref().name, "Hello 2".to_string());
assert_eq!(Arc::strong_count(&still_ts1), 1);
// We can now also take ownership of the Arc
let ts1_again = Arc::try_unwrap(still_ts1.consume()).unwrap();
assert_eq!(ts1_again, ts1);
}

@ -26,7 +26,6 @@
(defvaralias 'cperl-indent-level 'tab-width)
;;; Hide startup splash
;; FIXME: this doesn't currently work...
(setq inhibit-startup-screen t)
(setq inhibit-splash-screen t)
(setq initial-scratch-message nil)
@ -64,13 +63,16 @@
(add-hook 'find-file-hook (lambda () (ruler-mode 1)))
;;; Setup mitosis buffer splitting
(setq emacs-anchor default-directory)
(defun mitosis () (interactive) (make-frame))
(defalias 'mitosis 'make-frame)
;;; Distraction free mode and minimap
(require 'sublimity)
(require 'sublimity-attractive)
;;; Use the modeline from spacemacs
(require 'spaceline-config)
(spaceline-spacemacs-theme)
;;; OpenSCAD mode
(add-to-list 'auto-mode-alist '("\\.scad$" . scad-mode))
@ -139,4 +141,7 @@
(global-set-key (kbd "C-<prior>") 'previous-user-buffer)
(global-set-key (kbd "M-s M-s") 'save-buffer)
(global-set-key (kbd "C-t") 'smex)
(global-set-key (kbd "C-H-<left>") 'centaur-tabs-backward-tab)
(global-set-key (kbd "C-H-<right>") 'centaur-tabs-forward-tab)
(global-set-key (kbd "C-H-<up>") 'next-window-any-frame)
(global-set-key (kbd "C-H-<down>") 'previous-window-any-frame)

@ -6,4 +6,5 @@ with epkgs;
direnv
smex
sublimity
spaceline
])

@ -49,6 +49,13 @@ rec {
mkModPaths = modules: builtins.foldl' (acc: mod: acc ++ (unfold mod)) [] modules;
# Build the list of module names
mkModList = modules: map (m: m.name) modules;
# Extract emacs package dependencies
getUserEnvPkgs = with lib;
modules:
filter (f: f != null) (flatten
(concatMap
(mod: map (pkg: pkg.buildInputs ++ pkg.propagatedBuildInputs) mod.pkgs)
modules));
### Function invocations
modList = mkModList modules;
@ -64,7 +71,8 @@ rec {
mkdir -p $out/share/emacs/site-lisp/
cp ${loader} $out/share/emacs/site-lisp/default.el
'';
paths = modPaths ++ [ loaderWrap ];
pkgDependencies = getUserEnvPkgs modules;
paths = modPaths ++ pkgDependencies ++ [ loaderWrap ];
in
with pkgs;
symlinkJoin {

@ -34,7 +34,7 @@ pkgs.emacsWithPackages (epkgs:
protobuf-mode
raku-mode
scad-mode
# Utility moduse
fzf
magit
@ -44,4 +44,3 @@ pkgs.emacsWithPackages (epkgs:
vterm
which-key
])

@ -1,16 +1,4 @@
{ buildModule, epkgs, pkgs }:
with epkgs;
(buildModule "kookie-notmuch" ./. [ magit notmuch
## FIXME: installing "f" directly
## here is required because it is
## a dependency of many other
## tools, and installing magit
## seems to remove it from the
## emacs closure.
##
## Why? I don't know. Maybe one
## day we will understand.
f
])
(buildModule "kookie-notmuch" ./. [ magit notmuch ])

@ -8,11 +8,18 @@
;; LIBKOOKIE is licensed under the GPL-3.0 (or later) -- see LICENSE
(provide 'kookie-org)
;;; Setup org-roam basics
(require 'org)
(require 'ox-reveal)
(load-library "ox-reveal")
;;; Setup org-roam mode
(setq org-roam-v2-ack t)
(require 'org-roam)
(require 'org-roam-ui)
;;; Set .org as my file ending of choice
(add-to-list 'auto-mode-alist '("\\.org$" . org-mode))

@ -1,4 +1,10 @@
{ buildModule, epkgs, pkgs }:
with epkgs; with pkgs;
(buildModule "kookie-org" ./. [ org ox-reveal htmlize ])
(buildModule "kookie-org" ./. [
org
org-roam
org-roam-ui
ox-reveal
htmlize
])

@ -7,9 +7,6 @@ with epkgs; with pkgs;
# lsp integration
lsp-mode lsp-ui company
# ??? Not sure why these are required
dash-functional spinner
# projectile mode
projectile

@ -1,4 +1,3 @@
(provide 'theme)
(load-theme 'sanityinc-tomorrow-eighties t)

@ -0,0 +1 @@
eval "$(lorri direnv)"

@ -0,0 +1,81 @@
# craftlang
Craftlang (`.craft` files) is an expression language for crafting
recipies and block arrangement in the popular free software block
building game [Minetest](https://minetest.org). This tool is capable
of parsing `.craft` files and generating image outputs.
## Usage
This tool is written in [Raku](https://raku.org) and such you need to have `rakudo`
installed on your system. Additionally you need to make your minetest
assets tree and environment files available via ennvironment
variables.
```console
$ env MTCRAFT_ENV_PATH=/path/to/environments \
MINETEST_ASSETS=/path/to/minetest/assets/root \
craftlangc ./path-to-recipe.mtcraft
```
## Language overview
Craftlang is a domain-specific language for expressing recipes, based
on a small set of keywords, with associated payloads. A payload is
either a primitive or scope. Scopes use two-space indentation to
handle end-of-scope separation.
### Example
The following example should be enough to explain the basic structure
of primary mtcraft files.
```mtcraft
ENV alloys
INPUTS
copper_ingot 7
tin_ingot 1
OUTPUTS
bronze_ingot 8
```
The `ENV` keyword loads an environment file. Environment files add a
set of metadata which is added to a generated output, and also
provides a way to specify how other keywords are handled.
The `INPUTS` and `OUTPUTS` keywords open scopes. A scope is a set of
statements that is specific to the loaded environment but must be one
of the following: `key-value`, `marker` or `keyword`.
The example above contains three `key-value` statements. A `marker`
statement does not contain additional data and instead provides a
boolean flag to the environment. A `keyword` statement provides a way
to have nested `ENV`, `INPUTS`, and `OUTPUTS` scopes.
### Environment files
The environment provided via the `ENV` keyword must be present in the
`MTCRAFT_ENV_PATH`. An environment specifies the input-output
mappings for `INPUTS` and `OUTPUTS` scopes.
Required keywords for an ENV file are `BG`, `INPUTS`, `MODE`, and
`OUTPUTS`. The `SPACING` keyword is permitted outside of the `INPUTS`
and `OUTPUTS` blocks to be applied to both simultaniously. The `MODE`
keyword selects the general output mode. Currently accepted modes are
`crafting` and `arrangement`
```mtcraftenv
BG alloy_furnace
MODE crafting
SPACING 15 15
INPUTS
ANCHOR 125 125
COUNT 2 1
OUTPUTS
ANCHOR 525 125
COUNT 1 1
```
The default fill-mode is Left-to-right-top-to-bottom.

@ -0,0 +1,64 @@
#!/usr/bin/env raku
grammar FileGrammar {
# The top-level file is a list of statements
token TOP { ^ <line>* %% \v* $ }
# A line is either a list of keyword-payload or scope
token line { <statement> | <scope> }
# A statement is a simple keyword-payload mapping
token statement { <keyword> \s <payload> }
# The set of simple key-value keywords
token keyword { < ANCHOR BG COUNT ENV MODE SPACING > }
# A simple payload
token payload { \S+ %% \h* }
# A scope is a scope-word + list of scope-lines
token scope { <scope-word> <scope-line>* }
# The set of scope-opening keywords
token scope-word { < INPUTS OUTPUTS > }
# A scope line is either a simple payload or a full statement
token scope-line { \v+ \h \h [ <statement> | <payload> ] }
}
class Actions {
method TOP($/) {
make $<line>>>.made
}
method line($/) {
make .made with $<statement> || $<scope>;
}
method statement($/) {
make { Keyword => $<keyword>.made, Payload => $<payload>.made }
}
method scope($/) {
make { Keyword => $<scope-word>.made, Payload => $<scope-line>>>.made }
}
method scope-line($/) {
make $<statement> ?? $<statement>.made !! { Payload => $<payload>.made }
}
method keyword($/) { make ~$/ }
method payload($/) { make ~$/ }
method scope-word($/) { make ~$/ }
}
sub MAIN($file, Bool :$verbose) {
my $input = slurp $file;
say "Parsing input: $input" if $verbose;
my @parse = FileGrammar.parse($input, actions => Actions.new).made;
for @parse -> %line {
say %line
}
}

@ -0,0 +1 @@
import <shells/raku> {}

@ -0,0 +1,6 @@
ENV alloys
INPUTS
copper_ingot 7
tin_ingot 1
OUTPUTS
bronze_ingot 8
Loading…
Cancel
Save