|
Omg, I feel the unbearable pressure mounting up!
On top of that I am on a renewed energetic phase! So... perhaps I will!
But the fork, it turns out, was a bot from GitHub that check the dependencies are up to date!
|
|
|
|
|
Thanks, much as i like arcane arts, i need something robust enough to handle serializing multiple complex types ... no time to outfit my little library with multiple plug-and-play hot-swappable goodness
cheers, Bill
«The mind is not a vessel to be filled but a fire to be kindled» Plutarch
|
|
|
|
|
|
Bad news, the result of BinaryFormatter is far from a naked little nugget of raw bytes. It drops a ton of stupid stuff in there to describe the types, which your own format would never do because you already know what types you expect. It's the extra stuff that it puts in there that creates the vulnerabilities, so it's doubly bad.
|
|
|
|
|
Quote: It drops a ton of stupid stuff in there to describe the types
But it drops it binary
|
|
|
|
|
Hi Harold, i perceive your comment as being based on comparing a BinaryFormatter output to a "hand-rolled" serializer output. My statement was based on a comparison of XMLWriter output with BinaryFormatter.
cheers, Bill
«The mind is not a vessel to be filled but a fire to be kindled» Plutarch
|
|
|
|
|
Indeed. Confusing the BinaryFormatter and the BinaryReader / Writer.
"Before entering on an understanding, I have meditated for a long time, and have foreseen what might happen. It is not genius which reveals to me suddenly, secretly, what I have to say or to do in a circumstance unexpected by other people; it is reflection, it is meditation." - Napoleon I
|
|
|
|
|
I am sometimes awash with intellectual satisfaction how elegant is mouse handling thanks to those 2 guys!
So gonna show off my work in progress, doesn't do much but show off the structure, which is perfect, mouse down handling in my item tool!
What you can behold below is as follow...
When left click, count the click count, if any, then either start dragging (if still in mouse down) or add a text editor and wait for it to complete. All in one single async method. So simple to write. As simple as I just described, grooooovy!
protected internal override async void OnMapMouseDown(MouseButtonEventArgs e)
{
base.OnMapMouseDown(e);
var target = Target;
if (target == null)
return;
if (e.ChangedButton != MouseButton.Left)
return;
if (inMouseDown)
return;
inMouseDown = true;
try
{
using var uScope = Map.Document?.UndoManager.BeginScope();
var token = InputCancellationToken;
var p = e.GetPosition(Layer);
mouseDownLoc = target.Walls.Location(p.X, p.Y);
var isMouseStillDown = true;
await foreach (var (click, isIn) in GetClicksAsync(e, token))
{
isMouseStillDown = isIn;
Trace.WriteLine($"Got One: ({click}, {isIn})");
}
if (token.IsCancellationRequested)
return;
if (isMouseStillDown)
{
await foreach (var move in MapMouseDragAsync(e, token))
{
}
}
else
{
var anchor = new AnchorPoint(0.5, 0);
MapUtils.SetAutobounds(textEditor, () => p + anchor.OffsetFor(textEditor.TextBox, textEditor));
await MapUtils.EditAsync(Map, textEditor, token);
}
}
catch (TaskCanceledException) { }
finally
{
inMouseDown = false;
}
Trace.WriteLine("OnMapMouseDown over");
}
bool inMouseDown;
DD.TileLocation mouseDownLoc;
But what is the black magic behind, say MapMouseDragAsync , you may ask?
Also very simple, once again, behold!
Subject<EventArgs> mMapLeave = new();
Subject<MouseButtonEventArgs> mMapMouseUp = new();
Subject<MouseEventArgs> mMapMouseMove = new();
public IObservable<EventArgs> MapLeave => mMapLeave;
public IObservable<MouseButtonEventArgs> MapMouseUp => mMapMouseUp;
public IObservable<MouseEventArgs> MapMouseMove => mMapMouseMove;
protected internal virtual void OnMapLeave()
{
mMapLeave.OnNext(EventArgs.Empty);
mInputCancellationToken?.Cancel();
mInputCancellationToken = null;
}
protected internal virtual void OnMapMouseUp(MouseButtonEventArgs e) => mMapMouseUp.OnNext(e);
protected internal virtual void OnMapMouseMove(MouseEventArgs e) => mMapMouseMove.OnNext(e);
public async IAsyncEnumerable<MouseEventArgs> MapMouseDragAsync(MouseButtonEventArgs e, [EnumeratorCancellation] CancellationToken token)
{
if (e.ChangedButton != MouseButton.Left || Map.IsMouseCaptured)
yield break;
var captured = Map.CaptureMouse();
try
{
var events = this.MapMouseMove
.TakeUntil(this.MapMouseUp.Where(z => z.ChangedButton == MouseButton.Left))
.TakeUntil(this.MapLeave)
.ToAsyncEnumerable(token);
await foreach (var ev in events)
yield return ev;
}
finally
{
if (captured)
Map.ReleaseMouseCapture();
}
}
One can create observable directly from event, but I prefer to explicitly create Subject, since it's the class firing the event here, and I want to make observable easier.
modified 18-Dec-21 19:56pm.
|
|
|
|
|
This is probably just because I don't understand it yet, but it seems more complicated than the eventing model? I don't remember drag and drop requiring much aside from an event handler and setting a property or something. Maybe we're talking about something different? But I can't be sure because the code you posted doesn't make a lot of sense to me.
I haven't used async enumerable but I think I get it. It's just weird to me using it for drag and drop?
Real programmers use butterflies
|
|
|
|
|
you are thinking about dragging data.. which triggerr.. mmm.. some kind of special event...
Now I just show you in a single method, handling mouse down, up, click, and move something or, in this case or edit something.
Usually you have to override the 3 mouse method and have plenty of state variable laying around which track what you are currently doing. It's a pain.
|
|
|
|
|
Ah, I get you. Yeah I've done that before. It's not *as* bad if you can use lambdas for it instead of standard event handlers so you can capture, but it still gets ugly, I hear you.
Now I'm curious. So what are you doing exactly, enumerating over "events" asynchronously? (sorry I don't understand what the iterator methods you're calling return)
Edit: Never mind, I see it now.
Real programmers use butterflies
|
|
|
|
|
Yes you see it, nice!
Indeed the await foreach is enumerating events asynchronously!
modified 18-Dec-21 23:15pm.
|
|
|
|
|
This feels to me like something they'll have a better pattern for in .NET 8.
Still, it's cool. I've been looking for an application of IAsyncEnumerable, but I have yet to come up with much that's very compelling. Most of the time, since it's sequential and I can't return items in parallel anyway, each item depends on completing the previous one, no? If so, you only really get the benefit of the asynchronocity on the final item, unless I'm missing something - which I probably am.
If I'm reading a forward only stream for example, the next byte i read depends on me first having fetched the previous byte, which means i'm waiting on each element. Again, unless I'm missing something.
So I'm still trying to wrap my head around the async foreach.
Real programmers use butterflies
|
|
|
|
|
I think you missed something......
To answer the last question first, the only (very good) practical usage I found for IAsyncEnumrable so far is to enumerate events asynchronously. Events, as you know, happens later, much later, if at all!
So, to your first question:
Let's detail the mouse drag operation
When mouse down happen, I want to wait on next mouse move. I could have written code like that await NextMouseMoveasync()
This would have required lots of boilerplate code. Instead I started my work with reactive, an observable library, which let you manipulate, compose, analyze and action event stream (operators documentation). Really help for that kind of stuff.
It's great, but doesnt use async and the callback syntax for action on event can be complicated when you do lots of stuff. Anyway I much prefer async code to callback code. It's the same thing, but feels more.. straightforward? easier to read?
I can live with the funny exception callstack, but I so much more enjoy the improved code layout.
So next step was to turn this IObservable event stream into an IAsyncEnumerable , here just use the extension method ToAsyncEnumerable() .
and voila:
when I write
await foreach (var event Observable.Merge(MouseMove, MouseUp).ToAsynEnumerable())
I am asynchronously waiting for either next mouse move of mouse up, and handling it in the foreach body.
It's 100% asynchronous, what is enumerated here are mouse events, the foreach body is run on each mouse move event, which happens like once every 0.05 seconds, at best! And maybe not at all!
Does my explanation help shed some light?
Perhaps I should have trimmed my initial sample a bit.... mm..
modified 19-Dec-21 0:03am.
|
|
|
|
|
Yeah, I mean, it's advantageous when *one* item is going to take a long time, but I just don't run into that in the real world a lot. I understand why *you* are using it *here*, but I can't think of many places I'd actually need it outside replacing UI eventing code.
Real programmers use butterflies
|
|
|
|
|
ha well.. this code is all about event stream.
If you have to manipulate multiple events together it talks to you, otherwise it doesn't.
modified 19-Dec-21 0:44am.
|
|
|
|
|
Everything I touch over the past 48 hours just turns to garbage, codewise.
I think it's just a run of bad luck but it's super frustrating.
I try to get my SPI driver working, and I have massive timing problems.
I try getting sound working on my NES emulator and as soon as I enable it, boom - reboot loop
*sigh*
I'm afraid to do paying work right now because of it. I hate this.
Real programmers use butterflies
|
|
|
|
|
Don't worry, people who are paid to do work, introduce bugs in their paid time, true story!
|
|
|
|
|
Yeah but the next thing I have on my plate for work is bugfixing!
Real programmers use butterflies
|
|
|
|
|
You can't fix bugs if you don't write a few first.
|
|
|
|
|
Such wisdom!
|
|
|
|
|
You've obviously never had the misfortune of being part of the team like the one I was, a few years back.
It would've been fine if I was the silly monkey writing all the bugs...
Hate to imagine what being a medical doctor feels like!
|
|
|
|
|
Good morning,
honey the codewitch wrote: I try to get my SPI driver working, and I have massive timing problems. I'm looking at your st7789 code[^] and I don't see how it could ever work reliably in its current state. But it also looks like a relatively easy fix.
The datasheet[^] has a section labled 'Parallel Interface Timing Characteristics' which has a table containing the min/max wait and hold times. Why can't you just add a delay parameter to your command and data functions[^] and use os_delay_us() to wait for the period + hold.
Or you could just try taking the largest wait time and always wait for the maximum. For example, the largest write wait time I see in the st7789 datasheet appears to be 16ns.
Best Wishes,
-David Delaune
|
|
|
|
|
Here's the thing.
If I insert pauses between all my commands, my code will be the only code on the Internet that does that.
Seriously.
This code is basically copied, pasted, and the function names cleaned up - from a working library.
Now, I can insert delays to make my code slower.
But I darn well want to know why my code is the only one that needs delays.
Edit: I put delays everywhere. Same problem. *headdesk*
Real programmers use butterflies
modified 19-Dec-21 6:23am.
|
|
|
|
|
Hi,
honey the codewitch wrote: If I insert pauses between all my commands, my code will be the only code on the Internet that does that.
Are you sure about that? Look how the reference library you copied code from uses SPI_FREQUENCY[^] Also look at the busy-wait around the SPIBUSY[^] bits.
|
|
|
|
|