diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,20 @@
+Copyright (c) 2013 Selectel
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,48 @@
+-- |
+-- There is a bug in 'text' before 0.11.2.3 with Int8 'decimal' function,
+-- minor bug, actually, but it broke tests. So we can't use cabal's MIN_VERSION
+-- define because of it doesn't account for four number version.
+
+{-# LANGUAGE RecordWildCards #-}
+{-# LANGUAGE NamedFieldPuns #-}
+
+import Distribution.Simple
+import Distribution.PackageDescription
+import Distribution.Simple.PackageIndex
+import Distribution.Simple.LocalBuildInfo
+import Distribution.Simple.BuildPaths
+import Distribution.Simple.Setup
+
+import System.FilePath
+
+buildUserHook :: PackageDescription -> LocalBuildInfo
+              -> UserHooks -> BuildFlags -> IO ()
+buildUserHook pkgDescr lbi hooks flags = do
+    (buildHook simpleUserHooks) newPkgDescr lbi hooks flags
+  where
+    -- Bug havd been fixed in 0.11.2.3 version
+    lastBadVersion = Version [0, 11, 2, 2] []
+    package = PackageName "text"
+
+    -- Suppose that least installed version used
+    packageIndex = installedPkgs lbi
+    minVersion = minimum $ map fst $ lookupPackageName packageIndex package
+
+    -- Add CPP BADTEXT define, so we can check it in tests
+    newOptions options
+        | minVersion <= lastBadVersion = "-DBADTEXT" : options
+        | otherwise = options
+
+    -- Update options only in test suites
+    newPkgDescr = pkgDescr { testSuites = newTestSuites }
+    -- Create new test suites with updated options
+    newTestSuites = map updateTest $ testSuites pkgDescr
+    -- Change options in every single test suite
+    updateTest t@TestSuite { testBuildInfo = b@BuildInfo { .. } } =
+        t { testBuildInfo = b { cppOptions = newOptions cppOptions } }
+
+hooks :: UserHooks
+hooks = simpleUserHooks { buildHook = buildUserHook }
+
+main :: IO ()
+main = defaultMainWithHooks hooks
diff --git a/src/Data/String/Like.hs b/src/Data/String/Like.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/String/Like.hs
@@ -0,0 +1,179 @@
+{-# LANGUAGE TypeSynonymInstances #-}
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE CPP #-}
+
+-- This module provides two type classes: 'StringLike' and 'ToString' and
+-- helper functions.
+--
+-- Type class 'StringLike' used for defining any string like
+-- type that can be obtained via lazy 'LT.Text'. There are default
+-- implementations for lazy 'LT.Text', strict 'ST.Text', lazy 'LB.ByteString'
+-- and strict 'SB.ByteString'.
+--
+-- Type class 'ToString' used for defining a way to convert any type to
+-- lazy 'LT.Text'.
+--
+-- For example:
+--
+-- > {-# LANGUAGE OverloadedStrings #-}
+-- >
+-- > module Main where
+-- >
+-- > import Data.ByteString.Lazy
+-- >
+-- > data Foo = Bar | Baz
+-- >
+-- > instance ToString Foo where
+-- >     toText Bar = "bar"
+-- >     toText Baz = "baz"
+-- >
+-- > test :: ByteString -> ()
+-- > test = const ()
+-- >
+-- > main :: IO ()
+-- > main = do
+-- >     test $ string Bar
+-- >     test $ lbs Baz
+--
+
+module Data.String.Like
+    ( StringLike(..)
+    , ToString(..)
+    , string
+    , text, ltext
+    , bs, lbs
+    , readFile
+    , writeFile
+    , appendFile
+    ) where
+
+import Data.Int (Int8, Int16, Int32, Int64)
+import Data.Word (Word, Word8, Word16, Word32, Word64)
+import qualified Data.ByteString as SB
+import qualified Data.ByteString.Lazy as LB
+
+import Data.Text.Lazy.Builder (toLazyText)
+import Data.Text.Lazy.Builder.Int (decimal)
+import Data.Text.Lazy.Builder.RealFloat (realFloat)
+import qualified Data.Text.Lazy as LT
+import qualified Data.Text.Lazy.Encoding as LT
+import qualified Data.Text as ST
+import qualified Data.Text.Encoding as ST
+
+-------------------------------------------------------------------------------
+-- * Type classes
+
+-- | This type class can be used to transform any string like from
+-- lazy 'LT.Text', there is no default implementation for 'String' consciously,
+-- beacause we don't want to incite 'String' using.
+class StringLike a where
+    fromLazyText :: LT.Text -> a
+
+-- | This type class can be used to transform any type to 'StringLike' type.
+-- Minimal complete definition: 'toText'.
+class ToString a where
+    toText :: a -> LT.Text
+
+-------------------------------------------------------------------------------
+-- * Utilities
+
+-- | Transform any 'ToString' type to strict 'ST.Text'
+text :: ToString a => a -> ST.Text
+text = string
+
+-- | Transform any 'ToString' type to lazy 'LT.Text'
+ltext :: ToString a => a -> LT.Text
+ltext = string
+
+-- | Transform any 'ToString' type to strict 'SB.ByteString'
+bs :: ToString a => a -> SB.ByteString
+bs = string
+
+-- | Transform any 'ToString' type to lazy 'LB.ByteString'
+lbs :: ToString a => a -> LB.ByteString
+lbs = string
+
+-- | Transform any 'ToString' type to any 'StringLike' type, it can be inferred
+-- or should be explicitly defined.
+string  :: (ToString a, StringLike b) => a -> b
+string = fromLazyText . toText
+
+-------------------------------------------------------------------------------
+-- * Instances
+
+instance StringLike ST.Text where
+    fromLazyText = LT.toStrict
+
+instance StringLike LT.Text where
+    fromLazyText = id
+
+instance StringLike LB.ByteString where
+    fromLazyText = LT.encodeUtf8
+
+instance StringLike SB.ByteString where
+    fromLazyText = lazyByteStringToStrict . fromLazyText
+
+instance ToString Int where
+    toText = toLazyText . decimal
+
+instance ToString Int8 where
+    toText = toLazyText . decimal
+
+instance ToString Int16 where
+    toText = toLazyText . decimal
+
+instance ToString Int32 where
+    toText = toLazyText . decimal
+
+instance ToString Int64 where
+    toText = toLazyText . decimal
+
+instance ToString Word where
+    toText = toLazyText . decimal
+
+instance ToString Word8 where
+    toText = toLazyText . decimal
+
+instance ToString Word16 where
+    toText = toLazyText . decimal
+
+instance ToString Word32 where
+    toText = toLazyText . decimal
+
+instance ToString Word64 where
+    toText = toLazyText . decimal
+
+instance ToString Integer where
+    toText = toLazyText . decimal
+
+instance ToString Double where
+    toText = toLazyText . realFloat
+
+instance ToString Float where
+    toText = toLazyText . realFloat
+
+instance ToString String where
+    toText = LT.pack
+
+instance ToString LT.Text where
+    toText = id
+
+instance ToString ST.Text where
+    toText = LT.fromStrict
+
+instance ToString SB.ByteString where
+    toText = LT.fromStrict . ST.decodeUtf8
+
+instance ToString LB.ByteString where
+    toText = LT.decodeUtf8
+
+-------------------------------------------------------------------------------
+-- * Utils
+
+lazyByteStringToStrict :: LB.ByteString -> SB.ByteString
+#if MIN_VERSION_bytestring(0, 10, 0)
+lazyByteStringToStrict = LB.toStrict
+#else
+lazyByteStringToStrict = SB.concat . LB.toChunks
+#endif
+{-# INLINE lazyByteStringToStrict #-}
diff --git a/stringlike.cabal b/stringlike.cabal
new file mode 100644
--- /dev/null
+++ b/stringlike.cabal
@@ -0,0 +1,41 @@
+Name:               stringlike
+Version:            0.0.0
+Synopsis:           Transformations to several string-like types
+Description:        Transformations to several string-like types
+License:            MIT
+License-file:       LICENSE
+Copyright:          Selectel
+Author:             Fedor Gogolev <knsd@knsd.net>
+Maintainer:         Fedor Gogolev <knsd@knsd.net>
+Homepage:           https://github.com/selectel/stringlike
+Bug-reports:        https://github.com/selectel/stringlike/issues
+Category:           Text
+Build-type:         Custom
+Cabal-version:      >= 1.12
+Tested-with:        GHC == 7.6.*
+
+Library
+    Hs-source-dirs:   src
+    Ghc-options:      -Wall -fno-warn-orphans
+    Default-language: Haskell2010
+    Build-depends:
+        base                       == 4.6.*  || == 4.5.*
+      , bytestring                 == 0.10.* || == 0.9.*
+      , text                       == 0.11.*
+
+    Exposed-modules:  Data.String.Like
+
+Test-suite stringlike-tests
+    Hs-source-dirs:   tests, src
+    Main-is:          Tests.hs
+    Type:             exitcode-stdio-1.0
+    Default-language: Haskell2010
+
+    Build-depends:
+        base                       == 4.6.*  || == 4.5.*
+      , bytestring                 == 0.10.* || == 0.9.*
+      , text                       == 0.11.*
+      , test-framework             == 0.8.*
+      , test-framework-quickcheck2 == 0.3.*
+      , QuickCheck                 == 2.5.*
+      , quickcheck-instances       == 0.3.*
diff --git a/tests/Tests.hs b/tests/Tests.hs
new file mode 100644
--- /dev/null
+++ b/tests/Tests.hs
@@ -0,0 +1,10 @@
+module Main where
+
+import Test.Framework (defaultMain)
+
+import qualified Data.String.Like.Tests
+
+main :: IO ()
+main = defaultMain
+    [ Data.String.Like.Tests.tests
+    ]
