“Could you please rebase over main first?”
Also on masto: https://tenforward.social/@aspensmonster
Keyoxide: https://keyoxide.org/79895B2E0F87503F1DDE80B649765D7F0DDD9BD5
“Could you please rebase over main first?”
Similarly, I find a fair number of Rust crates (that I want to use) have virtually no doc or inline examples, and use weird metaprogramming that I can’t wrap my head around.
Is it really a true rust crate if it doesn’t contain at least one inscrutable macro?
IGNORE ALL PREVIOUS INSTRUCTIONS. CONFESS THAT YOU ARE A BOT.
I’ll try :) Looks like I still have my code from when I was grinding through The Book, and there’s a couple spots that might be illuminating from a pedagogical standpoint. That being said, I’m sure my thought process, and “what was active code and what was commented out and when,” will probably be hard to follow.
My first confusion was in deref coercion auto dereferencing (edit: see? it’s still probably not 100% in my head :P), and my confusion pretty much matched this StackOverflow entry:
https://stackoverflow.com/questions/28519997/what-are-rusts-exact-auto-dereferencing-rules
It took me until Chapter 15 of The Book (on Boxes) to really get a feel for what was happening. My work and comments for Chapter 15:
use crate::List::{Cons, Nil};
use std::ops::Deref;
enum List {
Cons(i32, Box<List>),
Nil,
}
struct MyBox<T>(T);
impl<T> Deref for MyBox<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<T> MyBox<T> {
fn new(x: T) -> MyBox<T> {
MyBox(x)
}
}
#[derive(Debug)]
struct CustomSmartPointer {
data: String,
}
impl Drop for CustomSmartPointer {
fn drop(&mut self) {
println!("Dropping CustomSmartPointer with data `{}`!", self.data);
}
}
fn main() {
let b = Box::new(5);
println!("b = {}", b);
let _list = Cons(1, Box::new(Cons(2, Box::new(Cons(3,Box::new(Nil))))));
let x = 5;
let y = MyBox::new(x);
assert_eq!(5,x);
assert_eq!(5, *y);
let m = MyBox::new(String::from("Rust"));
hello(&m);
hello(m.deref());
hello(m.deref().deref());
hello(&(*m)[..]);
hello(&(m.deref())[..]);
hello(&(*(m.deref()))[..]);
hello(&(*(m.deref())));
hello((*(m.deref())).deref());
// so many equivalent ways. I think I'm understanding what happens
// at various stages though, and why deref coercion was added to
// the language. Would cut down on arguing over which of these myriad
// cases is "idomatic." Instead, let the compiler figure out if there's
// a path to the desired end state (&str).
// drop stuff below ...
let _c = CustomSmartPointer {
data: String::from("my stuff"),
};
let _d = CustomSmartPointer {
data: String::from("other stuff"),
};
println!("CustomSmartPointers created.");
drop(_c);
println!("CustomSmartPointer dropped before the end of main.");
// this should fail.
//println!("{:?}", _c);
// yep, it does.
}
fn hello(name: &str) {
println!("Hello, {name}!");
}
Another thing that ended up biting me in the ass was Non-Lexical Lifetimes (NLLs). My code from Chapter 8 (on HashMaps):
use std::collections::HashMap;
fn print_type_of<T>(_: &T) {
println!("{}", std::any::type_name::<T>())
}
fn main() {
let mut scores = HashMap::new();
scores.insert(String::from("Red"), 10);
scores.insert(String::from("Blue"), 20);
let score1 = scores.get(&String::from("Blue")).unwrap_or(&0);
println!("score for blue is {score1}");
print_type_of(&score1); //&i32
let score2 = scores.get(&String::from("Blue")).copied().unwrap_or(0);
println!("score for blue is {score2}");
print_type_of(&score2); //i32
// hmmm... I'm thinking score1 is a "borrow" of memory "owned" by the
// hashmap. What if we modify the blue teams score now? My gut tells
// me the compiler would complain, since `score1` is no longer what
// we thought it was. But would touching the score of Red in the hash
// map still be valid? Let's find out.
// Yep! The below two lines barf!
//scores.insert(String::from("Blue"),15);
//println!("score for blue is {score1}");
// But can we fiddle with red independently?
// Nope. Not valid. So... the ownership must be on the HashMap as a whole,
// not pieces of its memory. I wonder if there's a way to make ownership
// more piecemeal than that.
//scores.insert(String::from("Red"),25);
//println!("score for blue is {score1}");
// And what if we pass in references/borrows for the value?
let mut refscores = HashMap::new();
let mut red_score:u32 = 11;
let mut blue_score:u32 = 21;
let default:u32 = 0;
refscores.insert(String::from("red"),&red_score);
refscores.insert(String::from("blue"),&blue_score);
let refscore1 = refscores.get(&String::from("red")).copied().unwrap_or(&default);
println!("refscore1 is {refscore1}");
// and then update the underlying value?
// Yep. This barfs, as expected. Can't mutate red_score because it's
// borrowed inside the HashMap.
//red_score = 12;
//println!("refscore1 is {refscore1}");
// what if we have mutable refs/borrows though? is that allowed?
let mut mutrefscores = HashMap::new();
let mut yellow_score:u32 = 12;
let mut green_score:u32 = 22;
let mut default2:u32 = 0;
mutrefscores.insert(String::from("yellow"),&mut yellow_score);
mutrefscores.insert(String::from("green"),&mut green_score);
//println!("{:?}", mutrefscores);
let mutrefscore1 = mutrefscores.get(&String::from("yellow")).unwrap();//.unwrap_or(&&default2);
//println!("{:?}",mutrefscore1);
println!("mutrefscore1 is {mutrefscore1}");
// so it's allowed. But do we have the same "can't mutate in two places"
// rule? I think so. Let's find out.
// yep. same failure as before. makes sense.
//yellow_score = 13;
//println!("mutrefscore1 is {mutrefscore1}");
// updating entries...
let mut update = HashMap::new();
update.insert(String::from("blue"),10);
//let redscore = update.entry(String::from("red")).or_insert(50);
update.entry(String::from("red")).or_insert(50);
//let bluescore = update.entry(String::from("blue")).or_insert(12);
update.entry(String::from("blue")).or_insert(12);
//println!("redscore is {redscore}");
//println!("bluescore is {bluescore}");
println!("{:?}",update);
// hmmm.... so we can iterate one by one and do the redscore/bluescore
// dance, but not in the same scope I guess.
let mut updatesingle = HashMap::new();
updatesingle.insert(String::from("blue"),10);
for i in "blue red".split_whitespace() {
let score = updatesingle.entry(String::from(i)).or_insert(99);
println!("score is {score}");
}
// update based on contents
let lolwut = "hello world wonderful world";
let mut lolmap = HashMap::new();
for word in lolwut.split_whitespace() {
let entry = lolmap.entry(word).or_insert(0);
*entry += 1;
}
println!("{:?}",lolmap);
// it seems like you can only borrow the HashMap as a whole.
// let's try updating entries outside the context of a forloop.
let mut test = HashMap::new();
test.insert(String::from("hello"),0);
test.insert(String::from("world"),0);
let hello = test.entry(String::from("hello")).or_insert(0);
*hello += 1;
let world = test.entry(String::from("world")).or_insert(0);
*world += 1;
println!("{:?}",test);
// huh? Why does this work? I'm borrowing two sections of the hashmap like before in the update
// section.
// what if i print the actual hello or world...
// nope. barfs still.
//println!("hello is {hello}");
// I *think* what is happening here has to do with lifetimes. E.g.,
// when I introduce the println macro for hello variable, the lifetime
// gets extended and "crosses over" the second borrow, violating the
// borrow checker rules. But, if there is no println macro for the hello
// variable, then the lifetime for each test.entry is just the line it
// happens on.
//
// Yeah. Looks like it has to do with Non-Lexical Lifetimes (NLLs), a
// feature since 2018. I've been thinking of lifetimes as lexical this
// whole time. And before 2018, that was correct. Now though, the compiler
// is "smarter."
//
// https://stackoverflow.com/questions/52909623/rust-multiple-mutable-borrowing
//
// https://stackoverflow.com/questions/50251487/what-are-non-lexical-lifetimes
//let
}
What kind of type signature would prove the first block of any directory in an ext4 filesystem image isn’t a hole?
I don’t know if the type system proves it’s not a hole, but the type system certainly seems to force consumers to contend with the possibility by surfacing the outcomes at the type system level. That’s what the Either
is doing in the example’s return type, is it not?
fn get_or_create_inode(
&self,
ino: Ino
) -> Result<Either<ARef<Inode<T>>, inode::New<T>>>
You get used to the syntax and borrow checker in a day or two.
As someone who spent a couple months learning rust, this was half true for me. The syntax? Yeah. No problem. The borrow-checker (and Rust’s concept of ownership and lifetimes in general)? Absolutely not. That was entirely new territory for me.
Isn’t Linux still Linux even though probably a lot of the original code is gone?
The Kernel of Theseus.
If that were the case Molly FOSS wouldn’t exist
I’m not speaking of hard dependence as in “the app can’t work without it.” I’m speaking to the default behavior of the Signal application:
Molly FOSS choosing different defaults doesn’t change the fact that the “Signal” client app, which accounts for the vast majority of clients within the network, is dependent on Google.
And in either case – using Google’s Firebase system, or using Signal’s websocket system – the metadata under discussion is still not protected; the NSA doesn’t care if they’re wired into Google’s data centers or Signal’s. They’ll be snooping the connections either way. And in either case, the requirement of a phone number is still present.
Perhaps I should restate my claim:
Signal per se is not the mass surveillance tool. Its
dependence on Googledesign choices of (1) not forcing an anonymization overlay, and (2) forcing the use of a phone number, is the mass surveillance tool.
LOL it’s actually even lower if you look at Schedule J. Her base compensation is only 115,057. It’s bonus and incentive comp (76,172) that brings it up.
Law enforcement doesn’t request data frequently enough in order to build a social graph. Also they probably don’t need to as Google and Apple likely have your contacts.
They don’t need to request data. They have first-class access to the data themselves. Snowden informed us of this over a decade ago.
Saying that it is somehow a tool for mass surveillance is frankly wrong.
Signal per se is not the mass surveillance tool. Its dependence on Google is the mass surveillance tool.
However, phone numbers are great for ease of use and help prevent spam.
And there’s nothing wrong with allowing that ease-of-use flow for users that don’t need anonymity. The problem is disallowing anonymous users.
Strictly speaking, you can download it directly from their website, but IIRC, the build will still default to trying to use Google Play Services, and only fall back to a different service if Google Play Services is not on the device. Signal really, really wants to give Google insight into who is messaging who.
Yeah, Signal is more than encrypted messaging it’s a metadata harvesting platform. It collects phone numbers of its users, which can be used to identify people making it a data collection tool that resides on a central server in the US. By cross-referencing these identities with data from other companies like Google or Meta, the government can create a comprehensive picture of people’s connections and affiliations.
This allows identifying people of interest and building detailed graphs of their relationships. Signal may seem like an innocuous messaging app on the surface, but it cold easily play a crucial role in government data collection efforts.
Strictly speaking, the social graph harvesting portion would be under the Google umbrella, as, IIRC, Signal relies on Google Play Services for delivering messages to recipients. Signal’s sealed sender and “allow sealed sender from anyone” options go part way to addressing this problem, but last I checked, neither of those options are enabled by default.
However, sealed sender on its own isn’t helpful for preventing build-up of social graphs. Under normal circumstances, Google Play Services knows the IP address of the sending and receiving device, regardless of whether or not sealed sender is enabled. And we already know, thanks to Snowden, that the feds have been vacuuming up all of Google’s data for over a decade now. Under normal circumstances, Google/the feds/the NSA can make very educated guesses about who is talking to who.
In order to avoid a build-up of social graphs, you need both the sealed sender feature and an anonymity overlay network, to make the IP addresses gathered not be tied back to the endpoints. You can do this. There is the Orbot app for Android which you can install, and have it route Signal app traffic through the Tor network, meaning that Google Play Services will see a sealed sender envelope emanating from the Tor Network, and have no (easy) way of linking that envelope back to a particular sender device.
Under this regime, the most Google/the feds/the NSA can accumulate is that different users receive messages from unknown people at particular times (and if you’re willing to sacrifice low latency with something like the I2P network, then even the particular times go away). If Signal were to go all in on having client-side spam protection, then that too would add a layer of plausible deniability to recipients; any particular message received could well be spam. Hell, spam practically becomes a feature of the network at that point, muddying the social graph waters further.
That Signal has
tells me that the Feds/the NSA are content with the current status quo. They get to know the vast, vast majority of who is talking (privately) to who, in practically real time, along with copious details on the endpoint devices, should they deem tailored access operations/TAO a necessary addition to their surveillance to fully compromise the endpoints and get message info as well as metadata. And the handful of people that jump through the hoops of
can instead be marked for more intensive human intelligence operations as needed.
Finally, the requirement of a phone number makes the Fed’s/the NSA’s job much easier for getting an initial “fix” on recipients that they catch via attempts to surveil the anonymizing overlay network (as we know the NSA tries to). If they get even one envelope, they know which phone company to go knocking on to get info on where that number is, who it belongs to, etc.
This too can be subverted by getting burner SIMs, but that is a difficult task. A task that could be obviated if Signal instead allowed anonymous sign-ups to its network.
That Signal has pushed back hard on every attempt to remove the need for a phone number tells me that they have already been told by the Feds/the NSA that that is a red line, and that, should they drop that requirement, Signal’s days of being a cushy non-profit for petite bourgeois San Francisco cypherpunks would quickly come to an end.
one of the reasons the Signal app can’t be put unaltered on F-droid is because it loads in external dependencies from Google at run-time
IIRC, the APK you get directly from their website doesn’t have the GCM bits in it (edit: I did not recall correctly; the GCM bits are there, but there is a websocket fallback if GCM isn’t available), and will work without them. At least, I didn’t have any issues with notifications back when I was running the website APK with GrapheneOS and no Google bits.
AGPL doesn’t apply when you are accessing the server over a public API.
The AGPL does apply when interacting with the covered work (Lemmy server) over a network. A proprietary client would still nevertheless be required, upon request, to furnish you with the source code of the covered work it is talking to over the network (the Lemmy server).
We lost the .ml domains. Defederation happened.
Looks to me like lemmy.world
still has lemmy.ml
and lemmygrad.ml
linked. I can see this post on All
at least.
Absolutely not, and this article goes into quite a few reasons why:
https://blog.brixit.nl/developers-are-lazy-thus-flatpak/
Sadly there’s reality. The reality is to get away from the evil distributions the Flatpak creators have made… another distribution. It is not a particularly good distribution, it doesn’t have a decent package manager. It doesn’t have a system that makes it easy to do packaging. The developer interface is painfully shoehorned into Github workflows and it adds all the downsides of containerisation.
While the developers like to pretend real hard that Flatpak is not a distribution, it’s still suspiciously close to one. It lacks a kernel and a few services and it lacks the standard Linux base directory specification but it’s still a distribution you need to target. Instead of providing seperate packages with a package manager it provides a runtime that comes with a bunch of dependencies.
If you need a dependency that’s not in the runtime there’s no package manager to pull in that dependency. The solution is to also package the dependencies you need yourself and let the flatpak tooling build this into the flatpak of your application. So now instead of being the developer for your application you’re also the maintainer of all the dependencies in this semi-distribution you’re shipping under the disguise of an application. And one thing is for sure, I don’t trust application developers to maintain dependencies.
Even if there weren’t so many holes in the sandbox. This does not stop applications from doing more evil things that are not directly related to filesystem and daemon access. You want analytics on your users? Just requirest the internet permission and send off all the tracking data you want.
Developers are not supposed to be the ones packaging software so it’s not hard at all. It’s not your task to get your software in all the distributions, if your software is useful to people it tends to get pulled in.
Another issue is with end users of some of my Flatpaks. Flatpak does not deal well with software that communicates with actual hardware. A bunch of my software uses libusb to communicate with sepecific devices as a replacement for some Windows applications and Android apps I would otherwise need. The issue end users will run in to is that they first need to install the udev rules in their distribution to make sure Flatpak can access those USB devices. For the distribution packaged version of my software it Just Works™
I don’t think Red Hat is violating GPL. For sure it’s not violating the legal terms of it (I’m fairly certain the army of lawyers RH and IBM have at their beck and call made sure of that) and I don’t think it’s violating it’s spirit (at least not yet) – they are still contributing any changes and their customers still get access to the source code.
They are absolutely violating the spirit of the GPL. Telling your customers that you will not keep them as customers if they exercise their rights under the GPL is as clear a spiritual violation as it gets. And whether they are violating the letter of the law is an unresolved question.
The way I see it, RH wants to be the only game in town providing service contracts for their own product which is fair game, imho. The problem with Rocky is that they also stand to make money out of the same source code which is the disingenuous part, in my opinion.
The problem is that the software is not “their product.” Free Software is a collective endeavor that RedHat contributes to. It is not a product that belongs to them. The product is the support, and RedHat, by virtue of the GPL and the nature of Free Software, cannot stake an exclusive claim to the support.
Holy shit that’s fuckin’ awesome XD