public static <A, B, C> PromiseWithoutUpdates<C> lift( final Lambda2<A, B, C> f, PromiseWithoutUpdates<A> pa, PromiseWithoutUpdates<B> pb) { return Transaction.run( () -> { class Tuple { Tuple(Optional<A> oa, Optional<B> ob) { this.oa = oa; this.ob = ob; } Optional<A> oa; Optional<B> ob; }; Lambda2<Tuple, Tuple, Tuple> combine = (l, r) -> new Tuple(l.oa.isPresent() ? l.oa : r.oa, l.ob.isPresent() ? l.ob : r.ob); Lambda1<Tuple, Optional<C>> result = t -> t.oa.isPresent() && t.ob.isPresent() ? Optional.of(f.apply(t.oa.get(), t.ob.get())) : Optional.empty(); Stream<Tuple> sA = pa.sDeliver.map(a -> new Tuple(Optional.of(a), Optional.empty())); Cell<Tuple> vA = pa.oValue.map(oa -> new Tuple(oa, Optional.empty())); Stream<Tuple> sB = pb.sDeliver.map(b -> new Tuple(Optional.empty(), Optional.of(b))); Cell<Tuple> vB = pb.oValue.map(ob -> new Tuple(Optional.empty(), ob)); Stream<Tuple> sAArrives = sA.snapshot(vB, combine); Stream<Tuple> sBArrives = sB.snapshot(vA, combine); Stream<Tuple> sSimultaneous = sA.merge(sB, combine); Stream<C> sDeliver = Stream.filterOptional(sAArrives.orElse(sBArrives).orElse(sSimultaneous).map(result)) .once(); Cell<Optional<C>> oValue = Cell.lift(combine, vA, vB).map(result); return new PromiseWithoutUpdates<C>(sDeliver, oValue); }); }
/** * Execute the specified code after the current transaction is closed, or immediately if there is * no current transaction. */ public static void post(final Runnable action) { Transaction.run( new Handler<Transaction>() { public void run(Transaction trans) { // -1 will mean it runs before anything split/deferred, and will run // outside a transaction context. trans.post_( -1, new Handler<Transaction>() { public void run(Transaction trans) { action.run(); } }); } }); }
public static void main(String[] args) { JFrame frame = new JFrame("form"); Listener l = Transaction.run( () -> { frame.setLayout(new FlowLayout()); SButton newClient = new SButton("Open new client"); frame.add(newClient); BackEnd be = new BackEnd(); Value<String> vName = be.allocate("name", "Joe Bloggs"); Value<Date> vBirthDate = be.allocate("birthDate", new Date(1980, 5, 1)); Value<Integer> vYear = vBirthDate.lens(d -> d.year, (dt, y) -> dt.setYear(y)); Value<Integer> vMonth = vBirthDate.lens(d -> d.month, (dt, y) -> dt.setMonth(y)); Value<Integer> vDay = vBirthDate.lens(d -> d.day, (dt, y) -> dt.setDay(y)); Bijection<Integer, String> toString = new Bijection<>( i -> Integer.toString(i), s -> { try { return Integer.parseInt(s); } catch (NumberFormatException e) { return 0; } }); Value<String> vYearStr = vYear.map(toString); Value<String> vMonthStr = vMonth.map(toString); Value<String> vDayStr = vDay.map(toString); frame.setSize(500, 250); frame.setVisible(true); return newClient.sClicked.listen( u -> { SwingUtilities.invokeLater( () -> { JFrame client = new JFrame("form client"); GridBagLayout gridbag = new GridBagLayout(); client.setLayout(gridbag); GridBagConstraints c = new GridBagConstraints(); c.fill = GridBagConstraints.HORIZONTAL; c.weighty = 0.0; c.weightx = 1.0; c.gridwidth = 1; c.gridheight = 1; c.gridx = 0; c.gridy = 0; Transaction.runVoid( () -> { c.gridx = 0; client.add(new JLabel("Name"), c); c.gridx = 1; c.gridwidth = 3; client.add(new VTextField(vName, 15), c); c.gridwidth = 1; c.gridy = 1; c.gridx = 0; client.add(new JLabel("Birth date"), c); c.gridx = 1; client.add(new VTextField(vYearStr, 4), c); c.gridx = 2; client.add(new VTextField(vMonthStr, 2), c); c.gridx = 3; client.add(new VTextField(vDayStr, 2), c); client.setSize(300, 100); client.setVisible(true); }); client.addWindowListener( new WindowAdapter() { public void windowClosing(WindowEvent e) { client.dispose(); } }); }); }); }); frame.addWindowListener( new WindowAdapter() { public void windowClosing(WindowEvent e) { l.unlisten(); System.exit(0); } }); while (true) { Runtime.getRuntime().gc(); try { Thread.sleep(1000); } catch (InterruptedException e) { } } }