Thursday, July 29, 2021

Gibson fretwire

Apparently with my Gibson Les Paul craze back again, I’ve been dabbling into the specs of the High Performance series. The specs list the fretwire as “Low”, without any further info on the actual dimensions. Also, other models are listed as having “Medium Jumbo” fretwire. What do they mean?

Fortunately Gibson Customer Service kindly answered my emails, and these are the measures:

Fretwire Height Width
Medium Jumbo .055" .090"
Low .045" .086"

This information, paired with this fretwire chart and our JP chart, gives us a good comparison with commonly known fret sizes:

Fretwire Height Width
Dunlop 6000 .058" .118"
6100 (Ibanez JPM) .055" .110"
6105 (Ibanez JEM) .055" .090"
6140 (Ibanez Universe) .039" .106"
EBMM medium jumbo (Majesty) .051" .108"
high wide (JP6) .047" .104"
Suhr jumbo .057" .110"
medium .055" .090"
heavy .051" .108"

I just can’t understand, however, why would they use vintage frets in such a modern guitar.

Sunday, July 11, 2021

Accepting both Vec or slice of String or &str in Rust

In whathever programming language, it’s rather common to have a function which accepts an array of strings. Specifically in Rust, there is the notion of slice, which can be used as a reference to a Vec. And also there is the notion of &str, which can be used as a reference to String. Putting both concepts together as an argument is not trivial, though.

Turns out I found a way to make it work by using the AsRef trait – as many things in Rust, traits lead the way. By using generics, it becomes possible:

fn foo<S: AsRef<str>>(names: &[S]) {
	for name in names.iter().map(|s| s.as_ref()) {
		println!("{}", name);
	}
}

Or alternatively using the impl keyword for the trait bound:

fn foo(names: &[impl AsRef<str>]) {
	for name in names.iter().map(|s| s.as_ref()) {
		println!("{}", name);
	}
}

The function above accepts both Vec and slice of String or &str. But notice how, in order to retrieve the string itself, the as_ref() method must be called.

Friday, July 9, 2021

About these 10 years

Hello, dear reader.

I started this blog exactly 10 years ago, in a Saturday morning, without having much idea about what I’d write here. I just wanted a safe place to vent.

Now, after 10 years, there’s quite an interesting content written down. In many ways, it’s a window to see my own maturing on various topics. Things that matter – or mattered at the time – to me, and nobody else. Well, actually some posts did generate outsiders’ interest but that’s not the point: this is a personal blog in the most actual sense.

But the thing is that it feels like it was yesterday. 10 years went by.

Thursday, July 1, 2021

Missing the ternary operator in Rust

Just out of curiosity, I wrote a Rust macro similar to Visual Basic’s IIf function:

macro_rules! iif {
	($cond:expr, $iftrue:expr, $iffalse:expr) => {
		if $cond { $iftrue } else { $iffalse }
	};
}

Usage:

let n = iif!(1 == 1, "yes", "no");

Close to the ternary operator, which I’m sorely missing in these Rust days.

Wednesday, June 16, 2021

Fixing the horrible Firefox 89 interface

In searching for a fix to the Firefox 89 Proton layout catastrophe, I found a very neat site which tries to summarize all the fixes that can be made in “userChrome.css” file, which can be found in about:profiles internal URL, and enabled with toolkit.legacyUserProfileCustomizations.stylesheets in about:config.

Unfortunately, it’s not possible to restore the menu icons, as of yet, but it’s still a relief from that disaster.

This is my hack for Linux:

/*** Tighten up drop-down/context/popup menu spacing ***/

menupopup > menuitem, menupopup > menu {
	padding-block: 4px !important;
}
:root {
	--arrowpanel-menuitem-padding: 4px 8px !important;
}

/*** Proton Tabs Tweaks ***/

/* Adjust tab corner shape, optionally remove space below tabs */

#tabbrowser-tabs {
	--user-tab-rounding: 0px;
}
@media (-moz-proton) {
	.tab-background {
		border-radius: var(--user-tab-rounding) var(--user-tab-rounding) 0px 0px !important;
		margin-block: 1px 0 !important;
	}
	#scrollbutton-up, #scrollbutton-down { /* 6/10/2021 */
		border-top-width: 1px !important;
		border-bottom-width: 0 !important;
	}
	/* Container color bar visibility */
	.tabbrowser-tab[usercontextid] > .tab-stack > .tab-background > .tab-context-line {
		margin: 0px max(calc(var(--user-tab-rounding) - 3px), 0px) !important;
	}
}

/* Inactive tabs: Separator line style */

@media (-moz-proton) {
	.tabbrowser-tab:not([selected=true]):not([multiselected=true]):not([beforeselected-visible="true"]) .tab-background {
		border-right: 1px solid rgba(0, 0, 0, .20) !important;
	}
	/* For dark backgrounds */
	[brighttext="true"] .tabbrowser-tab:not([selected=true]):not([multiselected=true]):not([beforeselected-visible="true"]) .tab-background {
		border-right: 1px solid var(--lwt-selected-tab-background-color, rgba(255, 255, 255, .20)) !important;
	}
	.tabbrowser-tab:not([selected=true]):not([multiselected=true]) .tab-background {
		border-radius: 0 !important;
	}
	/* Remove padding between tabs */
	.tabbrowser-tab {
		padding-left: 0 !important;
		padding-right: 0 !important;
	}
}

Wednesday, June 2, 2021

Go’s defer in Rust

One of my all-time favorite features of Go is the defer mechanism. It’s so incredibly simple, and so incredibly ingenious and useful. The fact the deferred statements are called during a panic unwind makes me want to use it in other languages, like Rust.

As for Rust, I’m aware of the scopeguard crate, but it seems to be an overkill to such a simple concept. Plus, it does some fishy workaround to make the FnOnce.

So I decided to write my own Rust version of the defer mechanism, which turns out to be a macro that hides the creation of an object. This object holds a FnOnce which runs when at the end of the scope via Drop trait:

/// Internal struct used by the `defer!` macro.
pub struct Defer<F: FnOnce()> {
	func: Option<F>,
}

impl<F: FnOnce()> Defer<F> {
	pub fn new(func: F) -> Self {
		Self { func: Some(func) }
	}
}

impl<F: FnOnce()> Drop for Defer<F> {
	fn drop(&mut self) {
		self.func.take().map(|f| f());
	}
}

/// Defers the execution of a block until the surrounding scope ends.
macro_rules! defer {
	( $($tt:tt)* ) => {
		let _deferred = crate::defer::Defer::new(|| { $($tt)* });
	};
}

Usage is straightforward:

#[macro_use] mod defer; // considering defer.rs at crate's root

fn main() {
	defer! { println!("hi"); }
}

Edit: I published the code above as a crate: defer-lite.

Saturday, May 29, 2021

Sum types in Go

One thing I always missed in Go was sum types. I’ve seen some discussion before. Although Go doesn’t have this as an explicit, native feature, I found a pattern that suits my needs by defining types and interfaces.

In the example below, I simulate a function that would load application resources, which can be extracted by ID, position or a string identifier. First, we define the interface and the subtypes:

type (
	// Variant type for: ResId, ResPos, ResStr.
	Res interface{ implRes() }

	ResId  uint32
	ResPos uint32
	ResStr string
)

func (ResId)  implRes() {}
func (ResPos) implRes() {}
func (ResStr) implRes() {}

The isRes() function acts like a “tag” for each subtype.

Now, a function that receives the variant type:

func LoadResource(variant Res) {
	switch v := variant.(type) {
	case ResId:
		println("ID", uint32(v))
	case ResPos:
		println("Position", uint32(v))
	case ResStr:
		println("String", string(v))
	default:
		panic("Res does not accept a nil value.")
	}
}

Usage is now trivial:

LoadResource(ResId(2001))
LoadResource(ResPos(4))
LoadResource(ResStr("MY_ICON"))

It’s clean and it works remarkably well. I applied this technique in my Windigo library.