001package arez;
002
003import grim.annotations.OmitSymbol;
004import grim.annotations.OmitType;
005import javax.annotation.Nonnull;
006import javax.annotation.Nullable;
007import java.util.Objects;
008import static org.realityforge.braincheck.Guards.*;
009
010/**
011 * An isolated Arez context.
012 */
013@OmitType( unless = "arez.enable_zones" )
014public final class Zone
015{
016  /**
017   * The optional name of the zone. Only non-null when names are enabled.
018   */
019  @Nullable
020  @OmitSymbol( unless = "arez.enable_names" )
021  private final String _name;
022  /**
023   * The underlying context for zone.
024   */
025  private final ArezContext _context = new ArezContext( this );
026
027  /**
028   * Return the context for the zone.
029   *
030   * @return the context for the zone.
031   */
032  @Nonnull
033  public ArezContext getContext()
034  {
035    return _context;
036  }
037
038  /**
039   * Create a zone with the specified name.
040   * Should only be done via {@link Arez} methods.
041   *
042   * @param name the name of the zone. Should be null if {@link Arez#areNamesEnabled()} returns false.
043   */
044  Zone( @Nullable final String name )
045  {
046    _name = Arez.areNamesEnabled() ? Objects.requireNonNull( name ) : null;
047  }
048
049  public boolean isActive()
050  {
051    return Arez.currentZone() == this;
052  }
053
054  /**
055   * Return the name of the zone if available.
056   *
057   * @return the name of the zone. Will be null if {@link Arez#areNamesEnabled()} returns false or if no name supplied.
058   */
059  @Nullable
060  public String getName()
061  {
062    if ( Arez.shouldCheckApiInvariants() )
063    {
064      apiInvariant( Arez::areNamesEnabled,
065                    () -> "Arez-0169: Zone.getName() invoked when Arez.areNamesEnabled() is false" );
066    }
067    return _name;
068  }
069
070  /**
071   * Run the specified function in the zone.
072   * Activate the zone on entry, deactivate on exit.
073   *
074   * @param <T>    The type of the value returned from function.
075   * @param action the function to execute.
076   * @return the value returned from function.
077   */
078  public <T> T safeRun( @Nonnull final SafeFunction<T> action )
079  {
080    Arez.activateZone( this );
081    try
082    {
083      return action.call();
084    }
085    finally
086    {
087      Arez.deactivateZone( this );
088    }
089  }
090
091  /**
092   * Run the specified function in the zone.
093   * Activate the zone on entry, deactivate on exit.
094   *
095   * @param <T>    The type of the value returned from function.
096   * @param action the function to execute.
097   * @return the value returned from function.
098   * @throws Throwable if the function throws an exception.
099   */
100  public <T> T run( @Nonnull final Function<T> action )
101    throws Throwable
102  {
103    Arez.activateZone( this );
104    try
105    {
106      return action.call();
107    }
108    finally
109    {
110      Arez.deactivateZone( this );
111    }
112  }
113
114  /**
115   * Run the specified procedure in the zone.
116   * Activate the zone on entry, deactivate on exit.
117   *
118   * @param action the procedure to execute.
119   */
120  public void safeRun( @Nonnull final SafeProcedure action )
121  {
122    Arez.activateZone( this );
123    try
124    {
125      action.call();
126    }
127    finally
128    {
129      Arez.deactivateZone( this );
130    }
131  }
132
133  /**
134   * Run the specified procedure in the zone.
135   * Activate the zone on entry, deactivate on exit.
136   *
137   * @param action the procedure to execute.
138   * @throws Throwable if the procedure throws an exception.
139   */
140  public void run( @Nonnull final Procedure action )
141    throws Throwable
142  {
143    Arez.activateZone( this );
144    try
145    {
146      action.call();
147    }
148    finally
149    {
150      Arez.deactivateZone( this );
151    }
152  }
153}