public void TestMapMemory() { int? beforeListenerCount = null; int? duringListenerCount = null; int? afterListenerCount = null; StreamSink<int> s = new StreamSink<int>(); Stream<string> m = s.Map(x => (x + 2).ToString()); List<string> @out = new List<string>(); dotMemory.Check(memory => beforeListenerCount = memory.GetObjects(where => where.Interface.Is<IListener>()).ObjectsCount); ((Action)(() => { using (m.Listen(@out.Add)) { dotMemory.Check(memory => duringListenerCount = memory.GetObjects(where => where.Interface.Is<IListener>()).ObjectsCount); s.Send(5); s.Send(3); } CollectionAssert.AreEqual(new[] { "7", "5" }, @out); }))(); dotMemory.Check(memory => afterListenerCount = memory.GetObjects(where => where.Interface.Is<IListener>()).ObjectsCount); Assert.IsNotNull(beforeListenerCount); Assert.IsNotNull(duringListenerCount); Assert.IsNotNull(afterListenerCount); Assert.AreEqual(beforeListenerCount, afterListenerCount, "Before == After"); Assert.IsTrue(duringListenerCount > beforeListenerCount, "During > Before"); }
public void TestCoalesce2() { StreamSink<int> s = new StreamSink<int>((x, y) => x + y); List<int> @out = new List<int>(); using (s.Listen(@out.Add)) { Transaction.RunVoid(() => { s.Send(1); s.Send(2); s.Send(3); s.Send(4); s.Send(5); }); Transaction.RunVoid(() => { s.Send(6); s.Send(7); s.Send(8); s.Send(9); s.Send(10); }); } CollectionAssert.AreEqual(new[] { 15, 40 }, @out.ToArray()); }
public void TestBaseSend1() { StreamSink<string> s = new StreamSink<string>(); List<string> @out = new List<string>(); using (s.Listen(@out.Add)) { s.Send("a"); s.Send("b"); } CollectionAssert.AreEqual(new[] { "a", "b" }, @out); }
public void TestHoldUpdates() { StreamSink<int> s = new StreamSink<int>(); Cell<int> c = s.Hold(0); List<int> @out = new List<int>(); using (Operational.Updates(c).Listen(@out.Add)) { s.Send(2); s.Send(9); } CollectionAssert.AreEqual(new[] { 2, 9 }, @out); }
public void TestHold() { StreamSink<int> e = new StreamSink<int>(); Cell<int> b = e.Hold(0); List<int> @out = new List<int>(); using (b.Listen(@out.Add)) { e.Send(2); e.Send(9); } CollectionAssert.AreEqual(new[] { 0, 2, 9 }, @out); }
public void TestHoldIsDelayed() { StreamSink<int> s = new StreamSink<int>(); Cell<int> h = s.Hold(0); Stream<string> pair = s.Snapshot(h, (a, b) => a + " " + b); List<string> @out = new List<string>(); using (pair.Listen(@out.Add)) { s.Send(2); s.Send(3); } CollectionAssert.AreEqual(new[] { "2 0", "3 2" }, @out); }
public void Run() { StreamSink<int> sX = new StreamSink<int>(); Stream<int> sXPlus1 = sX.Map(x => x + 1); using (Transaction.Run(() => { sX.Send(1); return sXPlus1.Listen(Console.WriteLine); })) { sX.Send(2); sX.Send(3); } }
public void TestAccum() { StreamSink<int> sa = new StreamSink<int>(); List<int> @out = new List<int>(); Cell<int> sum = sa.Accum(100, (a, s) => a + s); using (sum.Listen(@out.Add)) { sa.Send(5); sa.Send(7); sa.Send(1); sa.Send(2); sa.Send(3); } CollectionAssert.AreEqual(new[] { 100, 105, 112, 113, 115, 118 }, @out); }
public void TestNestedMapGarbageCollection() { int? beforeStreamCount = null; int? beforeListenerCount = null; int? duringStreamCount = null; int? duringListenerCount = null; int? afterStreamCount = null; int? afterListenerCount = null; StreamSink<int> s = new StreamSink<int>(); List<string> @out = new List<string>(); dotMemory.Check(memory => beforeStreamCount = memory.GetObjects(where => where.Type.Is<Stream<int>>()).ObjectsCount + memory.GetObjects(where => where.Type.Is<Stream<string>>()).ObjectsCount); dotMemory.Check(memory => beforeListenerCount = memory.GetObjects(where => where.Interface.Is<IListener>()).ObjectsCount); ((Action)(() => { Stream<string> m = s.Map(x => x + 2).Map(x => 2 * x).Map(x => x + 1).Map(x => x.ToString()); using (m.Listen(@out.Add)) { dotMemory.Check(memory => duringStreamCount = memory.GetObjects(where => where.Type.Is<Stream<int>>()).ObjectsCount + memory.GetObjects(where => where.Type.Is<Stream<string>>()).ObjectsCount); dotMemory.Check(memory => duringListenerCount = memory.GetObjects(where => where.Interface.Is<IListener>()).ObjectsCount); s.Send(5); s.Send(3); } CollectionAssert.AreEqual(new[] { "15", "11" }, @out); }))(); dotMemory.Check(memory => afterStreamCount = memory.GetObjects(where => where.Type.Is<Stream<int>>()).ObjectsCount + memory.GetObjects(where => where.Type.Is<Stream<string>>()).ObjectsCount); dotMemory.Check(memory => afterListenerCount = memory.GetObjects(where => where.Interface.Is<IListener>()).ObjectsCount); // although all listeners and streams have been cleand up, the nodes will not be disconnected until the stream fires next Assert.AreEqual(1, s.Node.GetListeners().Count); s.Send(1); Assert.AreEqual(0, s.Node.GetListeners().Count); Assert.IsNotNull(beforeStreamCount); Assert.IsNotNull(beforeListenerCount); Assert.IsNotNull(duringStreamCount); Assert.IsNotNull(duringListenerCount); Assert.IsNotNull(afterStreamCount); Assert.IsNotNull(afterListenerCount); Assert.AreEqual(beforeStreamCount, afterStreamCount, "Before Streams == After Streams"); Assert.AreEqual(beforeListenerCount, afterListenerCount, "Before Listeners == After Listeners"); Assert.IsTrue(duringStreamCount > beforeStreamCount, "During Streams > Before Streams"); Assert.IsTrue(duringListenerCount > beforeListenerCount, "During Listeners > Before Listeners"); }
public void TestSnapshot() { CellSink<int> c = new CellSink<int>(0); StreamSink<long> trigger = new StreamSink<long>(); List<string> @out = new List<string>(); using (trigger.Snapshot(c, (x, y) => x + " " + y).Listen(@out.Add)) { trigger.Send(100L); c.Send(2); trigger.Send(200L); c.Send(9); c.Send(1); trigger.Send(300L); } CollectionAssert.AreEqual(new[] { "100 0", "200 2", "300 1" }, @out); }
public void TestOperationalDefer1() { StreamSink<string> a = new StreamSink<string>(); Stream<string> b = Operational.Defer(a); List<string> @out = new List<string>(); using (b.Listen(@out.Add)) { a.Send("a"); } CollectionAssert.AreEqual(new[] { "a" }, @out); List<string> out2 = new List<string>(); using (b.Listen(out2.Add)) { a.Send("b"); } CollectionAssert.AreEqual(new[] { "b" }, out2); }
public void TestOperationalDeferSimultaneous() { StreamSink<string> a = new StreamSink<string>(); StreamSink<string> b = new StreamSink<string>(); Stream<string> c = Operational.Defer(a).OrElse(Operational.Defer(b)); List<string> @out = new List<string>(); using (c.Listen(@out.Add)) { b.Send("A"); } CollectionAssert.AreEqual(new[] { "A" }, @out); List<string> out2 = new List<string>(); using (c.Listen(out2.Add)) { Transaction.RunVoid(() => { a.Send("b"); b.Send("B"); }); } CollectionAssert.AreEqual(new[] { "b" }, out2); }
public SButton(Cell<bool> enabled) { StreamSink<Unit> sClickedSink = new StreamSink<Unit>(); this.SClicked = sClickedSink; this.Click += (sender, args) => sClickedSink.Send(Unit.Value); // Set the initial value at the end of the transaction so it works with CellLoops. Transaction.Post(() => this.IsEnabled = enabled.Sample()); // ReSharper disable once UseObjectOrCollectionInitializer List<IListener> listeners = new List<IListener>(); listeners.Add(Operational.Updates(enabled).Listen(e => this.Dispatcher.InvokeIfNecessary(() => this.IsEnabled = e))); this.listeners = listeners; }
public FrView(Window window, Fridget fr, IListener l) { StreamSink<MouseEvent> sMouse = new StreamSink<MouseEvent>(); StreamSink<KeyEvent> sKey = new StreamSink<KeyEvent>(); this.MouseDown += (sender, args) => sMouse.Send(new MouseEvent(args, () => args.GetPosition(this))); this.MouseUp += (sender, args) => sMouse.Send(new MouseEvent(args, () => args.GetPosition(this))); this.MouseMove += (sender, args) => sMouse.Send(new MouseEvent(args, () => args.GetPosition(this))); CellSink<IMaybe<Size>> size = new CellSink<IMaybe<Size>>(Maybe.Nothing<Size>()); this.SizeChanged += (sender, args) => size.Send(Maybe.Just(args.NewSize)); window.KeyDown += (sender, args) => { Key key = args.Key == Key.System ? args.SystemKey : args.Key; if (key == Key.Back) { sKey.Send(new BackspaceKeyEvent()); } }; window.TextInput += (sender, args) => sKey.Send(new StringKeyEvent(args.Text)); CellLoop<long> focus = new CellLoop<long>(); Fridget.Output fo = fr.Reify(size, sMouse, sKey, focus, new Supply()); focus.Loop(fo.SChangeFocus.Hold(-1)); this.drawable = fo.Drawable; this.l = new ImmutableCompositeListener(new[] { l, Operational.Updates(this.drawable).Listen(d => this.InvalidateVisual()) }); }
public async Task Run() { Console.WriteLine("*** test 1"); { StreamSink<string> s1 = new StreamSink<string>(); Task<string> t1 = s1.ListenOnce(); s1.Send("Early"); Console.WriteLine(await t1); } Console.WriteLine(); Console.WriteLine("*** test 2"); { StreamSink<string> s1 = new StreamSink<string>(); Task t1 = s1.ListenOnce().ContinueWith(t => Console.WriteLine(t.Result), TaskContinuationOptions.ExecuteSynchronously); s1.Send("Late"); await t1; } }
public void TestOrElseSimultaneous1() { StreamSink <int> s1 = Stream.CreateSink <int>((_, r) => r); StreamSink <int> s2 = Stream.CreateSink <int>((_, r) => r); List <int> @out = new List <int>(); IListener l = s2.OrElse(s1).Listen(@out.Add); Transaction.RunVoid(() => { s1.Send(7); s2.Send(60); }); Transaction.RunVoid(() => { s1.Send(9); }); Transaction.RunVoid(() => { s1.Send(7); s1.Send(60); s2.Send(8); s2.Send(90); }); Transaction.RunVoid(() => { s2.Send(8); s2.Send(90); s1.Send(7); s1.Send(60); }); Transaction.RunVoid(() => { s2.Send(8); s1.Send(7); s2.Send(90); s1.Send(60); }); l.Unlisten(); CollectionAssert.AreEqual(new[] { 60, 9, 90, 90, 90 }, @out); }
public SButton(Cell <Square> square) { StreamSink <Unit> sClickedSink = Stream.CreateSink <Unit>(); SClicked = sClickedSink; Click += (sender, args) => sClickedSink.Send(Unit.Value); StreamSink <Unit> sClickedRightSink = Stream.CreateSink <Unit>(); SClickedRight = sClickedRightSink; MouseRightButtonDown += (sender, args) => sClickedRightSink.Send(Unit.Value); // Set the initial value at the end of the transaction so it works with CellLoops. Transaction.Post(() => { var sample = square.Sample(); Content = sample.Content; FontWeight = sample.FontWeight; Foreground = sample.Foreground; Background = sample.Background; IsEnabled = sample.IsEnabled; }); // ReSharper disable once UseObjectOrCollectionInitializer List <IListener> listeners = new List <IListener>(); listeners.Add(square.Updates().Listen(e => Dispatcher.InvokeIfNecessary(() => { Content = e.Content; FontWeight = e.FontWeight; Foreground = e.Foreground; Background = e.Background; IsEnabled = e.IsEnabled; }))); this.listeners = listeners; }
public void SwitchEarlySCatchFirst() { List <int> output = new List <int>(); ValueTuple <Stream <int>, StreamSink <int>, StreamSink <int>, CellSink <Stream <int> >, IListener> t = Transaction.Run(() => { StreamSink <int> c1 = Stream.CreateSink <int>(); StreamSink <int> c2 = Stream.CreateSink <int>(); CellSink <Stream <int> > s = Cell.CreateSink(c1.AsStream()); Stream <int> c = s.SwitchEarlyS(); c1.Send(2); c2.Send(12); s.Send(c2); IListener l = c.Listen(output.Add); return(ValueTuple.Create(c, c1, c2, s, l)); }); t.Item2.Send(3); t.Item3.Send(13); Transaction.RunVoid(() => { t.Item2.Send(4); t.Item3.Send(14); t.Item4.Send(t.Item2); }); t.Item2.Send(5); t.Item3.Send(15); t.Item5.Unlisten(); CollectionAssert.AreEqual(new[] { 12, 13, 4, 5 }, output); }
public MainWindow() { this.InitializeComponent(); this.Loaded += async(sender, args) => { ITimerSystem <DateTime> sys = new SystemClockTimerSystem(e => this.Dispatcher.Invoke(() => { throw e; })); Cell <DateTime> time = sys.Time; StreamSink <Unit> sMain = new StreamSink <Unit>(); IListener l = Transaction.Run(() => { DateTime t0 = time.Sample(); IListener l1 = Periodic(sys, TimeSpan.FromSeconds(1)).Listen(t => this.AddMessage(t - t0 + " timer")); IListener l2 = sMain.Snapshot(time).Listen(t => this.AddMessage(t - t0 + " main")); return(new CompositeListener(new[] { l1, l2 })); }); for (int i = 0; i < 5; i++) { sMain.Send(Unit.Value); await Task.Delay(990); } l.Unlisten(); }; }
public void TestOperationalDefer2() { StreamSink <string> a = new StreamSink <string>(); StreamSink <string> b = new StreamSink <string>(); Stream <string> c = Operational.Defer(a).OrElse(b); List <string> @out = new List <string>(); using (c.Listen(@out.Add)) { a.Send("a"); } CollectionAssert.AreEqual(new[] { "a" }, @out); List <string> out2 = new List <string>(); using (c.Listen(out2.Add)) { Transaction.RunVoid(() => { a.Send("b"); b.Send("B"); }); } CollectionAssert.AreEqual(new[] { "B", "b" }, out2); }
public void TestListenWeakWithMap() { StreamSink <int> s = Stream.CreateSink <int>(); List <int> @out = new List <int>(); ((Action)(() => { Stream <int> s2 = s.Map(v => v + 1); ((Action)(() => { // ReSharper disable once UnusedVariable IWeakListener l = s2.ListenWeak(@out.Add); s.Send(1); s.Send(2); }))(); GC.Collect(0, GCCollectionMode.Forced); ((Action)(() => { // ReSharper disable once UnusedVariable IWeakListener l = s2.ListenWeak(@out.Add); s.Send(3); s.Send(4); s.Send(5); }))(); }))(); GC.Collect(0, GCCollectionMode.Forced); s.Send(6); s.Send(7); Assert.AreEqual(5, @out.Count); }
public async Task Run() { Console.WriteLine("*** test"); { StreamSink<string> s1 = new StreamSink<string>(); Task<string> t1 = s1.ListenOnce(); new Thread(() => { s1.Send("Sent"); }).Start(); Console.WriteLine(await t1); } }
public async Task Run() { Console.WriteLine("*** Simple test"); { StreamSink<string> sa = new StreamSink<string>(); StreamSink<string> sb = new StreamSink<string>(); Task<string> ta = sa.ListenOnce(); Task<string> tb = sb.ListenOnce(); new Thread(() => { sa.Send("Hello"); sb.Send("World"); }).Start(); Console.WriteLine(await ta + " " + await tb); } Console.WriteLine(); Console.WriteLine("*** Simultaneous case"); { StreamSink<string> sa = new StreamSink<string>(); StreamSink<string> sb = new StreamSink<string>(); Task<string> ta = sa.ListenOnce(); Task<string> tb = sb.ListenOnce(); new Thread(() => { Transaction.RunVoid(() => { sa.Send("Hello"); sb.Send("World"); }); }).Start(); Console.WriteLine(await ta + " " + await tb); } }
private static Tuple <Stream <T>, Dictionary <int, Action> > MkStream <T>(Dictionary <int, T> firings) { StreamSink <T> s = Stream.CreateSink <T>(); Dictionary <int, Action> f = firings.ToDictionary(firing => firing.Key, firing => (Action)(() => s.Send(firing.Value))); if (f.Keys.Any(k => k < 0)) { throw new InvalidOperationException("All firings must occur at T >= 0."); } Stream <T> returnStream = s; return(Tuple.Create(returnStream, f)); }
public Implementation(PetrolPumpWindow petrolPump) { SComboBox <IPump> logic = new SComboBox <IPump>( new IPump[] { new LifeCyclePump(), new AccumulatePulsesPump(), new ShowDollarsPump(), new ClearSalePump(), new KeypadPump(), new PresetAmountPump() }, p => p.GetType().FullName); petrolPump.LogicComboBoxPlaceholder.Children.Add(logic); STextField textPrice1 = new STextField("2.149") { Width = 100 }; petrolPump.Price1Placeholder.Children.Add(textPrice1); STextField textPrice2 = new STextField("2.341") { Width = 100 }; petrolPump.Price2Placeholder.Children.Add(textPrice2); STextField textPrice3 = new STextField("1.499") { Width = 100 }; petrolPump.Price3Placeholder.Children.Add(textPrice3); Func <string, double> parseDoubleSafe = s => { double n; if (double.TryParse(s, out n)) { return(n); } return(0.0); }; StreamSink <Key> sKey = new StreamSink <Key>(); Dictionary <Key, FrameworkElement> containersByKey = new Dictionary <Key, FrameworkElement> { { Key.One, petrolPump.Keypad1Button }, { Key.Two, petrolPump.Keypad2Button }, { Key.Three, petrolPump.Keypad3Button }, { Key.Four, petrolPump.Keypad4Button }, { Key.Five, petrolPump.Keypad5Button }, { Key.Six, petrolPump.Keypad6Button }, { Key.Seven, petrolPump.Keypad7Button }, { Key.Eight, petrolPump.Keypad8Button }, { Key.Nine, petrolPump.Keypad9Button }, { Key.Zero, petrolPump.Keypad0Button }, { Key.Clear, petrolPump.KeypadClearButton } }; foreach (KeyValuePair <Key, FrameworkElement> containerAndKey in containersByKey) { containerAndKey.Value.MouseDown += async(sender, args) => { if (args.LeftButton == MouseButtonState.Pressed) { await Task.Run(() => sKey.Send(containerAndKey.Key)); } }; } DiscreteCellLoop <UpDown> nozzle1 = new DiscreteCellLoop <UpDown>(); DiscreteCellLoop <UpDown> nozzle2 = new DiscreteCellLoop <UpDown>(); DiscreteCellLoop <UpDown> nozzle3 = new DiscreteCellLoop <UpDown>(); DiscreteCell <double> calibration = DiscreteCell.Constant(0.001); DiscreteCell <double> price1 = textPrice1.Text.Map(parseDoubleSafe); DiscreteCell <double> price2 = textPrice2.Text.Map(parseDoubleSafe); DiscreteCell <double> price3 = textPrice3.Text.Map(parseDoubleSafe); DiscreteCellSink <Stream <Unit> > csClearSale = new DiscreteCellSink <Stream <Unit> >(Sodium.Stream.Never <Unit>()); Stream <Unit> sClearSale = csClearSale.SwitchS(); StreamSink <int> sFuelPulses = new StreamSink <int>(); Cell <Outputs> outputs = logic.SelectedItem.Map( pump => pump.Create(new Inputs( nozzle1.Updates, nozzle2.Updates, nozzle3.Updates, sKey, sFuelPulses, calibration, price1, price2, price3, sClearSale))); DiscreteCell <Delivery> delivery = outputs.Map(o => o.Delivery).SwitchC(); DiscreteCell <string> presetLcd = outputs.Map(o => o.PresetLcd).SwitchC(); DiscreteCell <string> saleCostLcd = outputs.Map(o => o.SaleCostLcd).SwitchC(); DiscreteCell <string> saleQuantityLcd = outputs.Map(o => o.SaleQuantityLcd).SwitchC(); DiscreteCell <string> priceLcd1 = outputs.Map(o => o.PriceLcd1).SwitchC(); DiscreteCell <string> priceLcd2 = outputs.Map(o => o.PriceLcd2).SwitchC(); DiscreteCell <string> priceLcd3 = outputs.Map(o => o.PriceLcd3).SwitchC(); Stream <Unit> sBeep = outputs.Map(o => o.SBeep).SwitchS(); Stream <Sale> sSaleComplete = outputs.Map(o => o.SSaleComplete).SwitchS(); SoundPlayer beepPlayer = new SoundPlayer(GetResourceStream(@"sounds\beep.wav")); this.listeners.Add(sBeep.Listen(_ => new Thread(() => beepPlayer.PlaySync()) { IsBackground = true }.Start())); SoundPlayer fastRumblePlayer = new SoundPlayer(GetResourceStream(@"sounds\fast.wav")); Action stopFast = () => { }; void PlayFast() { ManualResetEvent mre = new ManualResetEvent(false); new Thread(() => { fastRumblePlayer.PlayLooping(); mre.WaitOne(); fastRumblePlayer.Stop(); }) { IsBackground = true }.Start(); stopFast = () => { mre.Set(); stopFast = () => { }; }; } SoundPlayer slowRumblePlayer = new SoundPlayer(GetResourceStream(@"sounds\slow.wav")); Action stopSlow = () => { }; void PlaySlow() { ManualResetEvent mre = new ManualResetEvent(false); new Thread(() => { slowRumblePlayer.PlayLooping(); mre.WaitOne(); slowRumblePlayer.Stop(); }) { IsBackground = true }.Start(); stopSlow = () => { mre.Set(); stopSlow = () => { }; }; } this.listeners.Add(delivery.Changes().Listen(d => { petrolPump.Dispatcher.InvokeIfNecessary(() => { if (d == Delivery.Fast1 || d == Delivery.Fast2 || d == Delivery.Fast3) { PlayFast(); } else { stopFast(); } if (d == Delivery.Slow1 || d == Delivery.Slow2 || d == Delivery.Slow3) { PlaySlow(); } else { stopSlow(); } }); })); StackPanel presetLcdStackPanel = new StackPanel { Orientation = Orientation.Horizontal }; petrolPump.PresetPlaceholder.Children.Add(presetLcdStackPanel); this.listeners.Add(presetLcd.Listen(t => petrolPump.Dispatcher.InvokeIfNecessary(() => petrolPump.SetLcdDigits(presetLcdStackPanel, t, 5, true)))); StackPanel saleCostStackPanel = new StackPanel { Orientation = Orientation.Horizontal }; petrolPump.DollarsPlaceholder.Children.Add(saleCostStackPanel); this.listeners.Add(saleCostLcd.Listen(t => petrolPump.Dispatcher.InvokeIfNecessary(() => petrolPump.SetLcdDigits(saleCostStackPanel, t, 5, true)))); StackPanel saleQuantityLcdStackPanel = new StackPanel { Orientation = Orientation.Horizontal }; petrolPump.LitersPlaceholder.Children.Add(saleQuantityLcdStackPanel); this.listeners.Add(saleQuantityLcd.Listen(t => petrolPump.Dispatcher.InvokeIfNecessary(() => petrolPump.SetLcdDigits(saleQuantityLcdStackPanel, t, 5, true)))); StackPanel priceLcd1StackPanel = new StackPanel { Orientation = Orientation.Horizontal }; petrolPump.Fuel1Placeholder.Children.Add(priceLcd1StackPanel); this.listeners.Add(priceLcd1.Listen(t => petrolPump.Dispatcher.InvokeIfNecessary(() => petrolPump.SetLcdDigits(priceLcd1StackPanel, t, 5, false)))); StackPanel priceLcd2StackPanel = new StackPanel { Orientation = Orientation.Horizontal }; petrolPump.Fuel2Placeholder.Children.Add(priceLcd2StackPanel); this.listeners.Add(priceLcd2.Listen(t => petrolPump.Dispatcher.InvokeIfNecessary(() => petrolPump.SetLcdDigits(priceLcd2StackPanel, t, 5, false)))); StackPanel priceLcd3StackPanel = new StackPanel { Orientation = Orientation.Horizontal }; petrolPump.Fuel3Placeholder.Children.Add(priceLcd3StackPanel); this.listeners.Add(priceLcd3.Listen(t => petrolPump.Dispatcher.InvokeIfNecessary(() => petrolPump.SetLcdDigits(priceLcd3StackPanel, t, 5, false)))); Dictionary <DiscreteCellLoop <UpDown>, Image> nozzles = new Dictionary <DiscreteCellLoop <UpDown>, Image> { { nozzle1, petrolPump.Nozzle1Image }, { nozzle2, petrolPump.Nozzle2Image }, { nozzle3, petrolPump.Nozzle3Image } }; this.listeners.AddRange(nozzles.Select(nozzle => nozzle.Key.Listen(p => petrolPump.Dispatcher.InvokeIfNecessary(() => nozzle.Value.Margin = p == UpDown.Up ? new Thickness(0, 0, 0, 0) : new Thickness(0, 30, 0, 0))))); foreach (KeyValuePair <DiscreteCellLoop <UpDown>, Image> nozzle in nozzles) { StreamSink <Unit> nozzleClicks = new StreamSink <Unit>(); nozzle.Value.MouseDown += async(sender, args) => { if (args.LeftButton == MouseButtonState.Pressed) { await Task.Run(() => nozzleClicks.Send(Unit.Value)); } }; nozzle.Key.Loop(nozzleClicks.Snapshot(nozzle.Key, (_, n) => n == UpDown.Down ? UpDown.Up : UpDown.Down).Hold(UpDown.Down)); } this.listeners.Add(sSaleComplete.Listen(sale => { Task.Run(() => { petrolPump.Dispatcher.InvokeIfNecessary(() => { SaleCompleteDialog dialog = new SaleCompleteDialog( sale.Fuel.ToString(), Formatters.FormatPrice(sale.Price, null), Formatters.FormatSaleCost(sale.Cost), Formatters.FormatSaleQuantity(sale.Quantity)); dialog.Owner = petrolPump; csClearSale.Send(dialog.SOkClicked); dialog.Show(); IListener l = null; // ReSharper disable once RedundantAssignment l = dialog.SOkClicked.Listen(_ => { petrolPump.Dispatcher.InvokeIfNecessary(() => dialog.Close()); // ReSharper disable once AccessToModifiedClosure l?.Unlisten(); }); }); }); })); Task.Run(async() => { while (true) { Transaction.RunVoid(() => { switch (delivery.Cell.Sample()) { case Delivery.Fast1: case Delivery.Fast2: case Delivery.Fast3: sFuelPulses.Send(40); break; case Delivery.Slow1: case Delivery.Slow2: case Delivery.Slow3: sFuelPulses.Send(2); break; } }); await Task.Delay(200).ConfigureAwait(false); } // ReSharper disable once FunctionNeverReturns }); }
public async Task Run() { Console.WriteLine("*** Simple test"); { StreamSink<string> sa = new StreamSink<string>(); StreamSink<string> sb = new StreamSink<string>(); Task<string> ta = sa.ListenOnce(); Task<string> tb = sb.ListenOnce(); Func<Task<string>> t = async () => await ta + " " + await tb; sa.Send("Hello"); Func<Task> task = () => t().ContinueWith(t1 => Console.WriteLine(t1.Result), TaskContinuationOptions.ExecuteSynchronously); sb.Send("World"); await task(); } Console.WriteLine(); Console.WriteLine("*** Simultaneous case"); { StreamSink<string> sa = new StreamSink<string>(); StreamSink<string> sb = new StreamSink<string>(); Task<string> ta = sa.ListenOnce(); Task<string> tb = sb.ListenOnce(); Func<Task<string>> t = async () => await ta + " " + await tb; Func<Task> task = () => t().ContinueWith(t1 => Console.WriteLine(t1.Result), TaskContinuationOptions.ExecuteSynchronously); Transaction.RunVoid(() => { sa.Send("Hello"); sb.Send("World"); }); await task(); } }
public void TestOrElseLeftBias() { StreamSink<int> s = new StreamSink<int>(); Stream<int> s2 = s.Map(x => 2 * x); List<int> @out = new List<int>(); using (s2.OrElse(s).Listen(@out.Add)) { s.Send(7); s.Send(9); } CollectionAssert.AreEqual(new[] { 14, 18 }, @out); }
private static Tuple <Stream <T>, ILookup <int, Action> > MkStream <T>(IReadOnlyList <Tuple <int, T> > firings, Func <T, T, T> coalesce) { StreamSink <T> s = Stream.CreateSink <T>(coalesce); ILookup <int, Action> f = firings.ToLookup(firing => firing.Item1, firing => (Action)(() => s.Send(firing.Item2))); if (f.Any(g => g.Key < 0)) { throw new InvalidOperationException("All firings must occur at T >= 0."); } Stream <T> returnStream = s; return(Tuple.Create(returnStream, f)); }
public void TestCollect() { StreamSink<int> sa = new StreamSink<int>(); List<int> @out = new List<int>(); Stream<int> sum = sa.Collect(Tuple.Create(100, true), (a, s) => { int outputValue = s.Item1 + (s.Item2 ? a * 3 : a); return Tuple.Create(outputValue, Tuple.Create(outputValue, outputValue % 2 == 0)); }); using (sum.Listen(@out.Add)) { sa.Send(5); sa.Send(7); sa.Send(1); sa.Send(2); sa.Send(3); } CollectionAssert.AreEqual(new[] { 115, 122, 125, 127, 130 }, @out); }
public void TestDefer() { StreamSink<char> s = new StreamSink<char>(); Cell<char> b = s.Hold(' '); List<char> @out = new List<char>(); using (Operational.Defer(s).Snapshot(b).Listen(@out.Add)) { s.Send('C'); s.Send('B'); s.Send('A'); } CollectionAssert.AreEqual(new[] { 'C', 'B', 'A' }, @out); }
public void TestStreamSend() { StreamSink<int> s = new StreamSink<int>(); List<int> @out = new List<int>(); using (s.Listen(@out.Add)) { s.Send(5); } CollectionAssert.AreEqual(new[] { 5 }, @out); s.Send(6); CollectionAssert.AreEqual(new[] { 5 }, @out); }
public void TestDiscreteCellLoopComplex() { StreamSink <int> s = new StreamSink <int>(); StreamSink <Tuple <int, int> > addItemStreamSink = new StreamSink <Tuple <int, int> >(); StreamSink <IReadOnlyList <TestObject> > removeItemsStreamSink = new StreamSink <IReadOnlyList <TestObject> >(); DiscreteCell <IReadOnlyList <TestObject> > listCell = Transaction.Run(() => { DiscreteCellLoop <IReadOnlyList <TestObject> > listCellLoop = new DiscreteCellLoop <IReadOnlyList <TestObject> >(); DiscreteCell <IReadOnlyList <TestObject> > listCellLocal = addItemStreamSink.OrElse(s.Map(v => Tuple.Create(v, v))).Map <Func <IReadOnlyList <TestObject>, IReadOnlyList <TestObject> > >(o => c => c.Concat(new[] { new TestObject(o.Item1, o.Item2) }).ToArray()) .Merge(removeItemsStreamSink.Map <Func <IReadOnlyList <TestObject>, IReadOnlyList <TestObject> > >(o => c => c.Except(o).ToArray()), (f, g) => c => g(f(c))) .Snapshot(listCellLoop, (f, c) => f(c)) .Hold(new TestObject[0]); listCellLoop.Loop(listCellLocal); return(listCellLocal); }); IListener l2 = Transaction.Run(() => { return(listCell.Values.Listen(c => Transaction.Post(() => { if (c.Any()) { Tuple <int, int> t = c.Last().BothNumbersCell.Cell.Sample(); if (t.Item1 == 9 && t.Item2 == 9) { addItemStreamSink.Send(Tuple.Create(0, 0)); } } }))); }); IListener l3 = Transaction.Run(() => listCell.Map(c => c.Select(o => o.RemoveStream.MapTo(new[] { o })).Merge((x, y) => x.Concat(y).ToArray())).SwitchS().Listen(o => Transaction.Post(() => removeItemsStreamSink.Send(o)))); IListener l4 = Transaction.Run(() => listCell.Map(c => c.Any() ? c.Last().Number1Cell.Lift(c.Last().Number2Cell, (x, y) => x == 9 && y == 9).Updates : Stream.Never <bool>()).SwitchS().Filter(v => v).Listen(_ => Transaction.Post(() => addItemStreamSink.Send(Tuple.Create(0, 0))))); List <IReadOnlyList <Tuple <int, int> > > @out = new List <IReadOnlyList <Tuple <int, int> > >(); IListener l = listCell.Map(c => c.Select(o => o.Number1Cell.Lift(o.Number2Cell, Tuple.Create)).Lift()).SwitchC().Listen(@out.Add); addItemStreamSink.Send(Tuple.Create(5, 2)); addItemStreamSink.Send(Tuple.Create(9, 2)); listCell.Cell.Sample()[0].Remove(); addItemStreamSink.Send(Tuple.Create(2, 9)); listCell.Cell.Sample()[1].ChangeNumber1(9); addItemStreamSink.Send(Tuple.Create(9, 9)); s.Send(5); s.Send(9); Transaction.RunVoid(() => { addItemStreamSink.Send(Tuple.Create(5, 5)); s.Send(5); }); listCell.Cell.Sample()[8].ChangeNumber2(9); listCell.Cell.Sample()[8].ChangeNumber1(9); l.Unlisten(); l2.Unlisten(); l3.Unlisten(); l4.Unlisten(); Tuple <int, int>[][] expected = { new Tuple <int, int> [0], new[] { Tuple.Create(5,2) }, new[] { Tuple.Create(5,2), Tuple.Create(9, 2) }, new[] { Tuple.Create(9,2) }, new[] { Tuple.Create(9,2), Tuple.Create(2, 9) }, new[] { Tuple.Create(9,2), Tuple.Create(9, 9) }, new[] { Tuple.Create(9,2), Tuple.Create(9, 9), Tuple.Create(0, 0) }, new[] { Tuple.Create(9,2), Tuple.Create(9, 9), Tuple.Create(0, 0), Tuple.Create(9, 9) }, new[] { Tuple.Create(9,2), Tuple.Create(9, 9), Tuple.Create(0, 0), Tuple.Create(9, 9), Tuple.Create(0, 0) }, new[] { Tuple.Create(9,2), Tuple.Create(9, 9), Tuple.Create(0, 0), Tuple.Create(9, 9), Tuple.Create(0, 0), Tuple.Create(5, 5) }, new[] { Tuple.Create(9,2), Tuple.Create(9, 9), Tuple.Create(0, 0), Tuple.Create(9, 9), Tuple.Create(0, 0), Tuple.Create(5, 5), Tuple.Create(9, 9) }, new[] { Tuple.Create(9,2), Tuple.Create(9, 9), Tuple.Create(0, 0), Tuple.Create(9, 9), Tuple.Create(0, 0), Tuple.Create(5, 5), Tuple.Create(9, 9), Tuple.Create(0, 0) }, new[] { Tuple.Create(9,2), Tuple.Create(9, 9), Tuple.Create(0, 0), Tuple.Create(9, 9), Tuple.Create(0, 0), Tuple.Create(5, 5), Tuple.Create(9, 9), Tuple.Create(0, 0), Tuple.Create(5, 5) }, new[] { Tuple.Create(9,2), Tuple.Create(9, 9), Tuple.Create(0, 0), Tuple.Create(9, 9), Tuple.Create(0, 0), Tuple.Create(5, 5), Tuple.Create(9, 9), Tuple.Create(0, 0), Tuple.Create(5, 9) }, new[] { Tuple.Create(9,2), Tuple.Create(9, 9), Tuple.Create(0, 0), Tuple.Create(9, 9), Tuple.Create(0, 0), Tuple.Create(5, 5), Tuple.Create(9, 9), Tuple.Create(0, 0), Tuple.Create(9, 9) }, new[] { Tuple.Create(9,2), Tuple.Create(9, 9), Tuple.Create(0, 0), Tuple.Create(9, 9), Tuple.Create(0, 0), Tuple.Create(5, 5), Tuple.Create(9, 9), Tuple.Create(0, 0), Tuple.Create(9, 9), Tuple.Create(0, 0) } }; Assert.AreEqual(expected.Length, @out.Count); for (int i = 0; i < 16; i++) { CollectionAssert.AreEqual(@out[i], expected[i]); } }
public void TestOrElseSimultaneous2() { StreamSink<int> s = new StreamSink<int>(); Stream<int> s2 = s.Map(x => 2 * x); List<int> @out = new List<int>(); using (s.OrElse(s2).Listen(@out.Add)) { s.Send(7); s.Send(9); } CollectionAssert.AreEqual(new[] { 7, 9 }, @out); }
public void TestOrElseSimultaneous1() { StreamSink<int> s1 = new StreamSink<int>((l, r) => r); StreamSink<int> s2 = new StreamSink<int>((l, r) => r); List<int> @out = new List<int>(); using (s2.OrElse(s1).Listen(@out.Add)) { Transaction.RunVoid(() => { s1.Send(7); s2.Send(60); }); Transaction.RunVoid(() => { s1.Send(9); }); Transaction.RunVoid(() => { s1.Send(7); s1.Send(60); s2.Send(8); s2.Send(90); }); Transaction.RunVoid(() => { s2.Send(8); s2.Send(90); s1.Send(7); s1.Send(60); }); Transaction.RunVoid(() => { s2.Send(8); s1.Send(7); s2.Send(90); s1.Send(60); }); } CollectionAssert.AreEqual(new[] { 60, 9, 90, 90, 90 }, @out); }
public void TestCalm() { StreamSink <int> s = Stream.CreateSink <int>(); List <int> @out = new List <int>(); IListener l = s.Calm().Listen(@out.Add); s.Send(2); s.Send(2); s.Send(2); s.Send(4); s.Send(2); s.Send(4); s.Send(4); s.Send(2); s.Send(2); s.Send(2); s.Send(2); s.Send(2); s.Send(4); s.Send(2); s.Send(4); s.Send(4); s.Send(2); s.Send(2); s.Send(2); s.Send(2); s.Send(2); s.Send(4); s.Send(2); s.Send(4); s.Send(4); s.Send(2); s.Send(2); s.Send(2); s.Send(2); s.Send(2); s.Send(4); s.Send(2); s.Send(4); s.Send(4); s.Send(2); s.Send(2); s.Send(2); s.Send(2); s.Send(2); s.Send(4); s.Send(2); s.Send(4); s.Send(4); s.Send(2); s.Send(2); l.Unlisten(); CollectionAssert.AreEqual(new[] { 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2 }, @out); }
public static Stream <IMaybe <string> > Lookup(Stream <string> sWord) { StreamSink <IMaybe <string> > sDefinition = new StreamSink <IMaybe <string> >(); IListener listener = sWord.ListenWeak(wrd => { Task.Run(() => { //System.out.println("look up " + wrd); IMaybe <string> def = Maybe.Nothing <string>(); try { Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); s.Connect("dict.org", 2628); NetworkStream ns = new NetworkStream(s); StreamReader r = new StreamReader(ns); StreamWriter w = new StreamWriter(ns); try { r.ReadLine(); w.WriteLine("DEFINE ! " + wrd); w.Flush(); string result = r.ReadLine(); if (result != null && result.StartsWith("150")) { result = r.ReadLine(); } if (result != null && result.StartsWith("151")) { StringBuilder b = new StringBuilder(); while (true) { string l = r.ReadLine(); if (l == ".") { break; } b.AppendLine(l); } def = Maybe.Just(b.ToString()); } else { MessageBox.Show("ERROR: " + result); } } finally { try { s.Close(); s.Dispose(); } catch { // ignored } } } catch (Exception e) { MessageBox.Show("ERROR: " + e); } finally { sDefinition.Send(def); } }); }); return(sDefinition.AddCleanup(listener)); }
public void TestCalm() { StreamSink <int> s = new StreamSink <int>(); List <int> @out = new List <int>(); using (s.Calm().Listen(@out.Add)) { s.Send(2); s.Send(2); s.Send(2); s.Send(4); s.Send(2); s.Send(4); s.Send(4); s.Send(2); s.Send(2); s.Send(2); s.Send(2); s.Send(2); s.Send(4); s.Send(2); s.Send(4); s.Send(4); s.Send(2); s.Send(2); s.Send(2); s.Send(2); s.Send(2); s.Send(4); s.Send(2); s.Send(4); s.Send(4); s.Send(2); s.Send(2); s.Send(2); s.Send(2); s.Send(2); s.Send(4); s.Send(2); s.Send(4); s.Send(4); s.Send(2); s.Send(2); s.Send(2); s.Send(2); s.Send(2); s.Send(4); s.Send(2); s.Send(4); s.Send(4); s.Send(2); s.Send(2); } CollectionAssert.AreEqual(new[] { 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2 }, @out); }
public void TestOrElseNonSimultaneous() { StreamSink<int> s1 = new StreamSink<int>(); StreamSink<int> s2 = new StreamSink<int>(); List<int> @out = new List<int>(); using (s1.OrElse(s2).Listen(@out.Add)) { s1.Send(7); s2.Send(9); s1.Send(8); } CollectionAssert.AreEqual(new[] { 7, 9, 8 }, @out); }
public void TestMergeSimultaneous() { StreamSink<int> s = new StreamSink<int>(); Stream<int> s2 = s.Map(x => 2 * x); List<int> @out = new List<int>(); using (s.Merge(s2, (x, y) => x + y).Listen(@out.Add)) { s.Send(7); s.Send(9); } CollectionAssert.AreEqual(new[] { 21, 27 }, @out); }
public SButton() { StreamSink<Unit> sClickedSink = new StreamSink<Unit>(); this.SClicked = sClickedSink; this.Click += async (sender, args) => await Task.Run(() => sClickedSink.Send(Unit.Value)); }
public Implementation(PetrolPumpWindow petrolPump) { SComboBox<IPump> logic = new SComboBox<IPump>( new IPump[] { new LifeCyclePump(), new AccumulatePulsesPump(), new ShowDollarsPump(), new ClearSalePump(), new KeypadPump(), new PresetAmountPump() }, p => p.GetType().FullName); petrolPump.LogicComboBoxPlaceholder.Children.Add(logic); STextField textPrice1 = new STextField("2.149") { Width = 100 }; petrolPump.Price1Placeholder.Children.Add(textPrice1); STextField textPrice2 = new STextField("2.341") { Width = 100 }; petrolPump.Price2Placeholder.Children.Add(textPrice2); STextField textPrice3 = new STextField("1.499") { Width = 100 }; petrolPump.Price3Placeholder.Children.Add(textPrice3); Func<string, double> parseDoubleSafe = s => { double n; if (double.TryParse(s, out n)) { return n; } return 0.0; }; StreamSink<Key> sKey = new StreamSink<Key>(); Dictionary<Key, FrameworkElement> containersByKey = new Dictionary<Key, FrameworkElement> { { Key.One, petrolPump.Keypad1Button }, { Key.Two, petrolPump.Keypad2Button }, { Key.Three, petrolPump.Keypad3Button }, { Key.Four, petrolPump.Keypad4Button }, { Key.Five, petrolPump.Keypad5Button }, { Key.Six, petrolPump.Keypad6Button }, { Key.Seven, petrolPump.Keypad7Button }, { Key.Eight, petrolPump.Keypad8Button }, { Key.Nine, petrolPump.Keypad9Button }, { Key.Zero, petrolPump.Keypad0Button }, { Key.Clear, petrolPump.KeypadClearButton } }; foreach (KeyValuePair<Key, FrameworkElement> containerAndKey in containersByKey) { containerAndKey.Value.MouseDown += async (sender, args) => { if (args.LeftButton == MouseButtonState.Pressed) { await Task.Run(() => sKey.Send(containerAndKey.Key)); } }; } CellLoop<UpDown> nozzle1 = new CellLoop<UpDown>(); CellLoop<UpDown> nozzle2 = new CellLoop<UpDown>(); CellLoop<UpDown> nozzle3 = new CellLoop<UpDown>(); Cell<double> calibration = Cell.Constant(0.001); Cell<double> price1 = textPrice1.Text.Map(parseDoubleSafe); Cell<double> price2 = textPrice2.Text.Map(parseDoubleSafe); Cell<double> price3 = textPrice3.Text.Map(parseDoubleSafe); CellSink<Stream<Unit>> csClearSale = new CellSink<Stream<Unit>>(Sodium.Stream.Never<Unit>()); Stream<Unit> sClearSale = csClearSale.SwitchS(); StreamSink<int> sFuelPulses = new StreamSink<int>(); Cell<Outputs> outputs = logic.SelectedItem.Map( pump => pump.Create(new Inputs( Operational.Updates(nozzle1), Operational.Updates(nozzle2), Operational.Updates(nozzle3), sKey, sFuelPulses, calibration, price1, price2, price3, sClearSale))); Cell<Delivery> delivery = outputs.Map(o => o.Delivery).SwitchC(); Cell<string> presetLcd = outputs.Map(o => o.PresetLcd).SwitchC(); Cell<string> saleCostLcd = outputs.Map(o => o.SaleCostLcd).SwitchC(); Cell<string> saleQuantityLcd = outputs.Map(o => o.SaleQuantityLcd).SwitchC(); Cell<string> priceLcd1 = outputs.Map(o => o.PriceLcd1).SwitchC(); Cell<string> priceLcd2 = outputs.Map(o => o.PriceLcd2).SwitchC(); Cell<string> priceLcd3 = outputs.Map(o => o.PriceLcd3).SwitchC(); Stream<Unit> sBeep = outputs.Map(o => o.SBeep).SwitchS(); Stream<Sale> sSaleComplete = outputs.Map(o => o.SSaleComplete).SwitchS(); SoundPlayer beepPlayer = new SoundPlayer(GetResourceStream(@"sounds\beep.wav")); this.listeners.Add(sBeep.Listen(_ => new Thread(() => beepPlayer.PlaySync()) { IsBackground = true }.Start())); SoundPlayer fastRumblePlayer = new SoundPlayer(GetResourceStream(@"sounds\fast.wav")); Action stopFast = () => { }; Action playFast = () => { ManualResetEvent mre = new ManualResetEvent(false); new Thread(() => { fastRumblePlayer.PlayLooping(); mre.WaitOne(); fastRumblePlayer.Stop(); }) { IsBackground = true }.Start(); stopFast = () => mre.Set(); }; SoundPlayer slowRumblePlayer = new SoundPlayer(GetResourceStream(@"sounds\slow.wav")); Action stopSlow = () => { }; Action playSlow = () => { ManualResetEvent mre = new ManualResetEvent(false); new Thread(() => { slowRumblePlayer.PlayLooping(); mre.WaitOne(); slowRumblePlayer.Stop(); }) { IsBackground = true }.Start(); stopSlow = () => mre.Set(); }; this.listeners.Add(delivery.Changes().Listen(d => { petrolPump.Dispatcher.InvokeIfNecessary(() => { if (d == Delivery.Fast1 || d == Delivery.Fast2 || d == Delivery.Fast3) { playFast(); } else { stopFast(); } if (d == Delivery.Slow1 || d == Delivery.Slow2 || d == Delivery.Slow3) { playSlow(); } else { stopSlow(); } }); })); StackPanel presetLcdStackPanel = new StackPanel { Orientation = Orientation.Horizontal }; petrolPump.PresetPlaceholder.Children.Add(presetLcdStackPanel); this.listeners.Add(presetLcd.Listen(t => petrolPump.Dispatcher.InvokeIfNecessary(() => petrolPump.SetLcdDigits(presetLcdStackPanel, t, 5, true)))); StackPanel saleCostStackPanel = new StackPanel { Orientation = Orientation.Horizontal }; petrolPump.DollarsPlaceholder.Children.Add(saleCostStackPanel); this.listeners.Add(saleCostLcd.Listen(t => petrolPump.Dispatcher.InvokeIfNecessary(() => petrolPump.SetLcdDigits(saleCostStackPanel, t, 5, true)))); StackPanel saleQuantityLcdStackPanel = new StackPanel { Orientation = Orientation.Horizontal }; petrolPump.LitersPlaceholder.Children.Add(saleQuantityLcdStackPanel); this.listeners.Add(saleQuantityLcd.Listen(t => petrolPump.Dispatcher.InvokeIfNecessary(() => petrolPump.SetLcdDigits(saleQuantityLcdStackPanel, t, 5, true)))); StackPanel priceLcd1StackPanel = new StackPanel { Orientation = Orientation.Horizontal }; petrolPump.Fuel1Placeholder.Children.Add(priceLcd1StackPanel); this.listeners.Add(priceLcd1.Listen(t => petrolPump.Dispatcher.InvokeIfNecessary(() => petrolPump.SetLcdDigits(priceLcd1StackPanel, t, 5, false)))); StackPanel priceLcd2StackPanel = new StackPanel { Orientation = Orientation.Horizontal }; petrolPump.Fuel2Placeholder.Children.Add(priceLcd2StackPanel); this.listeners.Add(priceLcd2.Listen(t => petrolPump.Dispatcher.InvokeIfNecessary(() => petrolPump.SetLcdDigits(priceLcd2StackPanel, t, 5, false)))); StackPanel priceLcd3StackPanel = new StackPanel { Orientation = Orientation.Horizontal }; petrolPump.Fuel3Placeholder.Children.Add(priceLcd3StackPanel); this.listeners.Add(priceLcd3.Listen(t => petrolPump.Dispatcher.InvokeIfNecessary(() => petrolPump.SetLcdDigits(priceLcd3StackPanel, t, 5, false)))); Dictionary<CellLoop<UpDown>, Image> nozzles = new Dictionary<CellLoop<UpDown>, Image> { { nozzle1, petrolPump.Nozzle1Image }, { nozzle2, petrolPump.Nozzle2Image }, { nozzle3, petrolPump.Nozzle3Image } }; this.listeners.AddRange(nozzles.Select(nozzle => nozzle.Key.Listen(p => petrolPump.Dispatcher.InvokeIfNecessary(() => nozzle.Value.Margin = p == UpDown.Up ? new Thickness(0, 0, 0, 0) : new Thickness(0, 30, 0, 0))))); foreach (KeyValuePair<CellLoop<UpDown>, Image> nozzle in nozzles) { StreamSink<Unit> nozzleClicks = new StreamSink<Unit>(); nozzle.Value.MouseDown += async (sender, args) => { if (args.LeftButton == MouseButtonState.Pressed) { await Task.Run(() => nozzleClicks.Send(Unit.Value)); } }; nozzle.Key.Loop(nozzleClicks.Snapshot(nozzle.Key, (_, n) => n == UpDown.Down ? UpDown.Up : UpDown.Down).Hold(UpDown.Down)); } this.listeners.Add(sSaleComplete.Listen(sale => { Task.Run(() => { petrolPump.Dispatcher.InvokeIfNecessary(() => { SaleCompleteDialog dialog = new SaleCompleteDialog( sale.Fuel.ToString(), Formatters.FormatPrice(sale.Price, null), Formatters.FormatSaleCost(sale.Cost), Formatters.FormatSaleQuantity(sale.Quantity)); dialog.Owner = petrolPump; csClearSale.Send(dialog.SOkClicked); dialog.Show(); IListener l = null; // ReSharper disable once RedundantAssignment l = dialog.SOkClicked.Listen(_ => { petrolPump.Dispatcher.InvokeIfNecessary(() => dialog.Close()); // ReSharper disable once AccessToModifiedClosure using (l) { } }); }); }); })); Task.Run(async () => { while (true) { Transaction.RunVoid(() => { switch (delivery.Sample()) { case Delivery.Fast1: case Delivery.Fast2: case Delivery.Fast3: sFuelPulses.Send(40); break; case Delivery.Slow1: case Delivery.Slow2: case Delivery.Slow3: sFuelPulses.Send(2); break; } }); await Task.Delay(200).ConfigureAwait(false); } // ReSharper disable once FunctionNeverReturns }); }
public void TestOnce() { StreamSink<char> s = new StreamSink<char>(); List<char> @out = new List<char>(); using (s.Once().Listen(@out.Add)) { s.Send('A'); s.Send('B'); s.Send('C'); } CollectionAssert.AreEqual(new[] { 'A' }, @out); }
public STextBox(Stream<string> setText, string initText, Cell<bool> enabled) { base.Text = initText; List<IListener> listeners = new List<IListener>(); StreamSink<int> sDecrement = new StreamSink<int>(); Cell<bool> allow = setText.Map(_ => 1).OrElse(sDecrement).Accum(0, (b, d) => b + d).Map(b => b == 0); StreamSink<string> sUserChanges = new StreamSink<string>(); this.SUserChanges = sUserChanges; this.Text = sUserChanges.Gate(allow).OrElse(setText).Hold(initText); TextChangedEventHandler textChangedEventHandler = (sender, args) => { string text = base.Text; this.Dispatcher.InvokeAsync(() => sUserChanges.Send(text)); }; this.TextChanged += textChangedEventHandler; // Set the initial value at the end of the transaction so it works with CellLoops. Transaction.Post(() => this.Dispatcher.InvokeIfNecessary(() => this.IsEnabled = enabled.Sample())); listeners.Add(setText.Listen(t => { this.Dispatcher.InvokeAsync(() => { this.TextChanged -= textChangedEventHandler; base.Text = t; this.TextChanged += textChangedEventHandler; sDecrement.Send(-1); }); })); listeners.Add(Operational.Updates(enabled).Listen(e => this.Dispatcher.InvokeIfNecessary(() => this.IsEnabled = e))); this.disposeListeners = () => { foreach (IListener l in listeners) { using (l) { } } }; }