diff --git a/.travis.yml b/.travis.yml index f54ee1c4e..a400aa144 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,4 @@ language: scala scala: - - 2.9.2 - 2.9.3 - 2.10.0 diff --git a/algebird-bijection/src/main/scala/com/twitter/algebird/bijection/AlgebirdBijections.scala b/algebird-bijection/src/main/scala/com/twitter/algebird/bijection/AlgebirdBijections.scala new file mode 100644 index 000000000..360642cee --- /dev/null +++ b/algebird-bijection/src/main/scala/com/twitter/algebird/bijection/AlgebirdBijections.scala @@ -0,0 +1,89 @@ +/* +Copyright 2012 Twitter, Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package com.twitter.algebird.bijection + +import com.twitter.algebird.{ Field, Group, Monoid, Ring, Semigroup } +import com.twitter.bijection.{ AbstractBijection, Bijection, ImplicitBijection, Conversion, Reverse } + +import Conversion.asMethod // "as" syntax + +/** + * Bijections on Algebird's abstract algebra datatypes. + * + * @author Oscar Boykin + * @author Sam Ritchie + */ + +class BijectedSemigroup[T, U](implicit val sg: Semigroup[T], bij: ImplicitBijection[T, U]) extends Semigroup[U] { + def bijection: Bijection[U, T] = bij.bijection.inverse + override def plus(l: U, r: U): U = sg.plus(l.as[T], r.as[T]).as[U] +} + +class BijectedMonoid[T, U](implicit val monoid: Monoid[T], bij: ImplicitBijection[T, U]) extends BijectedSemigroup[T, U] with Monoid[U] { + override def zero: U = monoid.zero.as[U] +} + +class BijectedGroup[T, U](implicit val group: Group[T], bij: ImplicitBijection[T, U]) extends BijectedMonoid[T, U] with Group[U] { + override def negate(u: U): U = group.negate(u.as[T]).as[U] + override def minus(l: U, r: U): U = group.minus(l.as[T], r.as[T]).as[U] +} + +class BijectedRing[T, U](implicit val ring: Ring[T], bij: ImplicitBijection[T, U]) extends BijectedGroup[T, U] with Ring[U] { + override def one: U = ring.one + override def times(l: U, r: U): U = ring.times(l.as[T], r.as[T]).as[U] + override def product(iter: TraversableOnce[U]): U = + ring.product(iter map { _.as[T] }).as[U] +} + +class BijectedField[T, U](implicit val field: Field[T], bij: ImplicitBijection[T, U]) extends BijectedRing[T, U] with Field[U] { + override def div(l: U, r: U): U = field.div(l.as[T], r.as[T]).as[U] + override def inverse(u: U): U = field.inverse(u.as[T]).as[U] +} + +trait AlgebirdBijections { + implicit def semigroupBijection[T, U](implicit bij: ImplicitBijection[T, U]): Bijection[Semigroup[T], Semigroup[U]] = + new AbstractBijection[Semigroup[T], Semigroup[U]] { + override def apply(sg: Semigroup[T]) = new BijectedSemigroup[T, U]()(sg, bij) + override def invert(sg: Semigroup[U]) = new BijectedSemigroup[U, T]()(sg, Reverse(bij.bijection)) + } + + implicit def monoidBijection[T, U](implicit bij: ImplicitBijection[T, U]): Bijection[Monoid[T], Monoid[U]] = + new AbstractBijection[Monoid[T], Monoid[U]] { + override def apply(mon: Monoid[T]) = new BijectedMonoid[T, U]()(mon, bij) + override def invert(mon: Monoid[U]) = new BijectedMonoid[U, T]()(mon, Reverse(bij.bijection)) + } + + implicit def groupBijection[T, U](implicit bij: ImplicitBijection[T, U]): Bijection[Group[T], Group[U]] = + new AbstractBijection[Group[T], Group[U]] { + override def apply(group: Group[T]) = new BijectedGroup[T, U]()(group, bij) + override def invert(group: Group[U]) = new BijectedGroup[U, T]()(group, Reverse(bij.bijection)) + } + + implicit def ringBijection[T, U](implicit bij: ImplicitBijection[T, U]): Bijection[Ring[T], Ring[U]] = + new AbstractBijection[Ring[T], Ring[U]] { + override def apply(ring: Ring[T]) = new BijectedRing[T, U]()(ring, bij) + override def invert(ring: Ring[U]) = new BijectedRing[U, T]()(ring, Reverse(bij.bijection)) + } + + implicit def fieldBijection[T, U](implicit bij: ImplicitBijection[T, U]): Bijection[Field[T], Field[U]] = + new AbstractBijection[Field[T], Field[U]] { + override def apply(field: Field[T]) = new BijectedField[T, U]()(field, bij) + override def invert(field: Field[U]) = new BijectedField[U, T]()(field, Reverse(bij.bijection)) + } +} + +object AlgebirdBijections extends AlgebirdBijections diff --git a/algebird-bijection/src/test/scala/com/twitter/algebird/bijection/AlgebirdBijectionLaws.scala b/algebird-bijection/src/test/scala/com/twitter/algebird/bijection/AlgebirdBijectionLaws.scala new file mode 100644 index 000000000..91b05f6b8 --- /dev/null +++ b/algebird-bijection/src/test/scala/com/twitter/algebird/bijection/AlgebirdBijectionLaws.scala @@ -0,0 +1,24 @@ +/* + * Copyright 2010 Twitter Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.twitter.algebird.bijection + +import org.scalacheck.{ Arbitrary, Properties } + +object AlgebirdBijectionLaws extends Properties("AlgebirdBijections") { + // TODO: Fill in tests. Ideally we'd publish an algebird-testing + // module before merging this in. +} diff --git a/project/Build.scala b/project/Build.scala index 6930af5ab..c9146aa40 100644 --- a/project/Build.scala +++ b/project/Build.scala @@ -7,10 +7,17 @@ import com.typesafe.tools.mima.plugin.MimaPlugin.mimaDefaultSettings import com.typesafe.tools.mima.plugin.MimaKeys.previousArtifact object AlgebirdBuild extends Build { + def withCross(dep: ModuleID) = + dep cross CrossVersion.binaryMapped { + case "2.9.3" => "2.9.2" // TODO: hack because twitter hasn't built things against 2.9.3 + case version if version startsWith "2.10" => "2.10" // TODO: hack because sbt is broken + case x => x + } + val sharedSettings = Project.defaultSettings ++ releaseSettings ++ Seq( organization := "com.twitter", - scalaVersion := "2.9.2", - crossScalaVersions := Seq("2.9.2", "2.9.3", "2.10.0", "2.10.1"), + scalaVersion := "2.9.3", + crossScalaVersions := Seq("2.9.3", "2.10.0", "2.10.1"), resolvers ++= Seq( "snapshots" at "http://oss.sonatype.org/content/repositories/snapshots", @@ -83,47 +90,38 @@ object AlgebirdBuild extends Build { ).aggregate( algebirdTest, algebirdCore, - algebirdUtil + algebirdUtil, + algebirdBijection ) - lazy val algebirdCore = Project( - id = "algebird-core", - base = file("algebird-core"), - settings = sharedSettings - ).settings( + def module(name: String) = { + val id = "algebird-%s".format(name) + Project(id = id, base = file(id), settings = sharedSettings ++ Seq( + Keys.name := id, + previousArtifact := youngestForwardCompatible(name)) + ) + } + + lazy val algebirdCore = module("core").settings( test := { }, // All tests reside in algebirdTest - name := "algebird-core", initialCommands := """ import com.twitter.algebird._ """.stripMargin('|'), - previousArtifact := youngestForwardCompatible("core"), libraryDependencies += "com.googlecode.javaewah" % "JavaEWAH" % "0.6.6" ) - lazy val algebirdTest = Project( - id = "algebird-test", - base = file("algebird-test"), - settings = sharedSettings - ).settings( - name := "algebird-test", - previousArtifact := youngestForwardCompatible("test"), + lazy val algebirdTest = module("test").settings( libraryDependencies ++= Seq( "org.scalacheck" %% "scalacheck" % "1.10.0", "org.scala-tools.testing" %% "specs" % "1.6.9" ) ).dependsOn(algebirdCore) - lazy val algebirdUtil = Project( - id = "algebird-util", - base = file("algebird-util"), - settings = sharedSettings - ).settings( - name := "algebird-util", - previousArtifact := youngestForwardCompatible("util"), - libraryDependencies += "com.twitter" %% "util-core" % "6.3.0" cross CrossVersion.binaryMapped { - case "2.9.3" => "2.9.2" // TODO: hack because twitter hasn't built things against 2.9.3 - case version if version startsWith "2.10" => "2.10" // TODO: hack because sbt is broken - case x => x - } - ).dependsOn(algebirdCore, algebirdTest % "compile->test") + lazy val algebirdUtil = module("util").settings( + libraryDependencies += withCross("com.twitter" %% "util-core" % "6.3.0") + ).dependsOn(algebirdCore, algebirdTest % "test->compile") + + lazy val algebirdBijection = module("bijection").settings( + libraryDependencies += "com.twitter" %% "bijection-core" % "0.5.2" + ).dependsOn(algebirdCore, algebirdTest % "test->compile") }