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); }); }
void close() { while (true) { checkRegen(); if (prioritizedQ.isEmpty()) break; Entry e = prioritizedQ.remove(); entries.remove(e); e.action.run(this); } for (Runnable action : lastQ) action.run(); lastQ.clear(); if (postQ != null) { while (!postQ.isEmpty()) { Iterator<Map.Entry<Integer, Handler<Transaction>>> iter = postQ.entrySet().iterator(); if (iter.hasNext()) { Map.Entry<Integer, Handler<Transaction>> e = iter.next(); int ix = e.getKey(); Handler<Transaction> h = e.getValue(); iter.remove(); Transaction parent = currentTransaction; try { if (ix >= 0) { Transaction trans = new Transaction(); currentTransaction = trans; try { h.run(trans); } finally { trans.close(); } } else { currentTransaction = null; h.run(null); } } finally { currentTransaction = parent; } } } } }
/** * Run the specified code inside a single transaction, with the contained code returning a value * of the parameter type A. * * <p>In most cases this is not needed, because the primitives always create their own transaction * automatically, but it is needed in some circumstances. */ public static <A> A run(Lambda0<A> code) { synchronized (transactionLock) { // If we are already inside a transaction (which must be on the same // thread otherwise we wouldn't have acquired transactionLock), then // keep using that same transaction. Transaction transWas = currentTransaction; try { startIfNecessary(); return code.apply(); } finally { if (transWas == null) currentTransaction.close(); currentTransaction = transWas; } } }
static void run(Handler<Transaction> code) { synchronized (transactionLock) { // If we are already inside a transaction (which must be on the same // thread otherwise we wouldn't have acquired transactionLock), then // keep using that same transaction. Transaction transWas = currentTransaction; try { startIfNecessary(); code.run(currentTransaction); } finally { if (transWas == null) currentTransaction.close(); currentTransaction = transWas; } } }
/** * 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) { } } }
public final void thenDo(Handler<A> h) { Transaction.runVoid(() -> then().listenOnce(h)); }